tanstack/markdown · Archived

octane-rendering

Render Markdown source or a MarkdownDocument with @tanstack/markdown/octane using Markdown, renderMarkdownOctane, ComponentBody replacements, TSRX, and octane/server static SSR. Load for Octane descriptors, custom emitted tags, pre-parsed documents, SSR return values, or renderer parity.

First seen Aug 23, 2026

Installation

$ npx skills add tanstack/markdown --skill octane-rendering

Stronger alternatives

This repository is archived — consider an actively maintained alternative.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from tanstack/markdown.

npx skills add tanstack/markdown

Browse all from tanstack/markdown

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 126
Default branch main
Open issues 4
Status Archived

Skill metadata

Parsed from SKILL.md frontmatter.

More metadata
type
framework
library
@tanstack/markdown
framework
octane
library_version
0.0.13

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 8,637 B
  • docs SUMMARY.md 312 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 3 installs

SKILL.md

This skill builds on [render-markdown](../render-markdown/SKILL.md). Read it first for the syntax profile, parser options, AST, and core trust boundaries.

Octane Rendering

Setup

Install the optional Octane peer and render a fragment descriptor:

pnpm add @tanstack/markdown octane
import { createElement } from 'octane'
import { Markdown } from '@tanstack/markdown/octane'

export function Article({ source }: { source: string }) {
  return createElement(
    'article',
    null,
    Markdown({
      children: source,
    }),
  )
}

The adapter requires [email protected] or newer. Markdown returns an ElementDescriptor, not an HTML string.

Hooks and Components

Render Markdown from TSRX

import { Markdown } from '@tanstack/markdown/octane'

export function Article({ source }: { source: string }) @{
  <article>
    <Markdown>{source}</Markdown>
  </article>
}

The component returns an Octane fragment descriptor, so the application owns the surrounding semantic element.

Replace emitted links with an Octane component

import { createElement, type ComponentBody } from 'octane'
import { Markdown } from '@tanstack/markdown/octane'

const ArticleLink: ComponentBody<any> = props => {
  const external =
    typeof props.href === 'string' && props.href.startsWith('http')

  return createElement('a', {
    ...props,
    rel: external ? 'noreferrer' : props.rel,
    target: external ? '_blank' : props.target,
  })
}

export function Article({ source }: { source: string }) {
  return Markdown({
    children: source,
    components: { a: ArticleLink },
  })
}

components accepts host tag strings or Octane ComponentBody values keyed by emitted tag name.

Render static markup and styles

import { renderToStaticMarkup } from 'octane/server'
import { Markdown } from '@tanstack/markdown/octane'

const source = '# Server-rendered article'

export const { html, css } = renderToStaticMarkup(Markdown, {
  children: source,
})

octane/server returns an object containing both html and css.

Parse once before repeated Octane rendering

import { parseMarkdown } from '@tanstack/markdown/parser'
import { Markdown } from '@tanstack/markdown/octane'

const document = parseMarkdown('# Cached article\n\nRendered from an AST.')

export const article = Markdown({
  children: document,
})

Apply parser options and document transforms before caching the document.

Compose through the lower-level node API

import { Fragment, createElement } from 'octane'
import { parseMarkdown } from '@tanstack/markdown/parser'
import { renderMarkdownOctane } from '@tanstack/markdown/octane'

const document = parseMarkdown('# Parsed once')

export function ArticleBody() {
  return createElement(
    Fragment,
    null,
    ...renderMarkdownOctane(document),
  )
}

Use renderBlockOctane or renderInlineOctane only when custom tree composition needs individual public AST nodes.

Common Mistakes

HIGH Treating descriptors as HTML strings

Wrong:

import { Markdown } from '@tanstack/markdown/octane'

const source = '# Article'

export const html = String(Markdown({ children: source }))

Correct:

import { renderToStaticMarkup } from 'octane/server'
import { Markdown } from '@tanstack/markdown/octane'

const source = '# Article'

export const { html } = renderToStaticMarkup(Markdown, {
  children: source,
})

Markdown returns an ElementDescriptor; serialize it through octane/server when an HTML string is required.

Source: docs/reference/octane.md

HIGH Using a React component in the map

Wrong:

import type { ComponentProps } from 'react'
import { Markdown } from '@tanstack/markdown/octane'

function ReactLink(props: ComponentProps<'a'>) {
  return <a {...props} />
}

export const article = Markdown({
  children: '[Guide](/guide)',
  components: { a: ReactLink },
})

Correct:

import { createElement, type ComponentBody } from 'octane'
import { Markdown } from '@tanstack/markdown/octane'

const OctaneLink: ComponentBody<any> = props =>
  createElement('a', {
    ...props,
    'data-navigation': 'article',
  })

export const article = Markdown({
  children: '[Guide](/guide)',
  components: { a: OctaneLink },
})

Octane replacements must be host tag strings or Octane ComponentBody values.

Source: docs/guides/octane.md

MEDIUM Ignoring the static-render return structure

Wrong:

import { renderToStaticMarkup } from 'octane/server'
import { Markdown } from '@tanstack/markdown/octane'

export const markup = renderToStaticMarkup(Markdown, {
  children: '# Article',
})

Correct:

import { renderToStaticMarkup } from 'octane/server'
import { Markdown } from '@tanstack/markdown/octane'

export const { html, css } = renderToStaticMarkup(Markdown, {
  children: '# Article',
})

The static renderer returns { html, css }, not a bare HTML string.

Source: docs/guides/octane.md

HIGH Expecting HTML extension hooks in Octane

Wrong:

import type { MarkdownExtension } from '@tanstack/markdown'
import { Markdown } from '@tanstack/markdown/octane'

const paragraphHtml: MarkdownExtension = {
  name: 'paragraph-html',
  renderHtml(node) {
    return node.type === 'paragraph'
      ? '<aside>Rendered only by the HTML renderer</aside>'
      : undefined
  },
}

export const article = Markdown({
  children: 'Ordinary content',
  extensions: [paragraphHtml],
})

Correct:

import type { MarkdownExtension } from '@tanstack/markdown'
import { createElement, type ComponentBody } from 'octane'
import { Markdown } from '@tanstack/markdown/octane'

const panelExtension: MarkdownExtension = {
  name: 'panel',
  transformDocument(document) {
    return {
      ...document,
      children: [
        {
          type: 'component',
          name: 'panel',
          tagName: 'doc-panel',
          attributes: {},
          children: document.children,
        },
      ],
    }
  },
}

const Panel: ComponentBody<any> = props =>
  createElement('aside', {
    ...props,
    className: 'documentation-panel',
  })

export const article = Markdown({
  children: 'Ordinary content',
  components: { 'doc-panel': Panel },
  extensions: [panelExtension],
})

MarkdownExtension.renderHtml is HTML-specific; portable custom output uses ComponentNode and an emitted-tag component mapping.

Source: docs/guides/extensions.md

CRITICAL Enabling raw HTML for untrusted input

Wrong:

import { Markdown } from '@tanstack/markdown/octane'

export function UserPost({ source }: { source: string }) {
  return Markdown({
    allowHtml: true,
    children: source,
  })
}

Correct:

import { Markdown } from '@tanstack/markdown/octane'

export function UserPost({ source }: { source: string }) {
  return Markdown({
    children: source,
  })
}

With allowHtml, Octane receives dangerouslySetInnerHTML; TanStack Markdown does not sanitize that raw HTML.

Source: docs/core-concepts/security.md

HIGH Tension: renderer parity versus Octane customization

Core Octane static output is tested against renderHtml(). Octane component replacements, raw HTML, highlighter output, and HTML-only extension hooks are application-controlled boundaries outside that parity guarantee.

See also: [custom-extensions](../custom-extensions/SKILL.md) for portable ComponentNode output.

Cross-References

  • [render-markdown](../render-markdown/SKILL.md) - shared MarkdownInput, parser options, AST behavior, and syntax profile.
  • [custom-extensions](../custom-extensions/SKILL.md) - emit custom tags that Octane can replace through components.
  • [production-pipelines](../production-pipelines/SKILL.md) - audit raw HTML, highlighter output, untrusted content, and static SSR boundaries.