
Skill
integrate-framework-code-blocks
integrate code blocks into web frameworks
Description
Integrate @tanstack/highlight with React code-block props, Octane dangerouslySetInnerHTML data, createOctaneMdxHighlight, hydrated SSR, and post-navigation client content. Load when implementing application-owned code components or sharing highlighted output across server and client.
SKILL.md
This skill requires configure-selective-highlighting and integrate-markdown-pipelines. Read them first for registry and tree-transform behavior.
Integrate Framework Code Blocks
Integration Setup
Create the highlighter in an isomorphic module, then pass it into the adapter:
import { createHighlighter } from '@tanstack/highlight/core'
import { ts } from '@tanstack/highlight/languages/ts'
import { tsx } from '@tanstack/highlight/languages/tsx'
import { createHighlightedCodeBlockProps } from '@tanstack/highlight/react'
const highlighter = createHighlighter({ languages: [ts, tsx] })
export const block = createHighlightedCodeBlockProps({
highlighter,
code: 'const answer = 42',
lang: 'ts',
title: 'answer.ts',
className: 'docs-code',
})
The adapters import no React, Octane, or MDX runtime and register no languages.
Core Integration Patterns
Render React-owned controls around generated markup
import type { HighlightedCodeBlockProps } from '@tanstack/highlight/react'
export function CodeBlock({
className,
copyText,
htmlMarkup,
title,
}: HighlightedCodeBlockProps) {
return (
<figure className={className}>
{title ? <figcaption>{title}</figcaption> : null}
<div dangerouslySetInnerHTML={{ __html: htmlMarkup }} />
<button
type="button"
onClick={() => navigator.clipboard.writeText(copyText)}
>
Copy
</button>
</figure>
)
}
Copy controls, tabs, filenames, and layout remain application-owned.
Configure Octane MDX with a plugin tuple
import { octaneMdx } from '@octanejs/mdx/vite'
import { createOctaneMdxHighlight } from '@tanstack/highlight/octane'
import { highlighter } from './src/highlight'
export default {
plugins: [
octaneMdx({
rehypePlugins: [
createOctaneMdxHighlight({
highlighter,
lineNumbers: true,
}),
],
}),
],
}
The tuple wraps the synchronous Rehype adapter expected by @octanejs/mdx.
Highlight only content introduced after hydration
import { highlighter } from './highlight'
export function renderClientNavigationCode(code: string, lang: string) {
return highlighter.renderCodeBlockData({ code, lang })
}
Initial server-rendered code is already static highlighted HTML; use the client registry for new routes, previews, or interactive source changes.
Common Mistakes
HIGH Nesting complete markup inside code
Wrong:
import { createHighlightedCodeBlockProps } from '@tanstack/highlight/react'
import { highlighter } from './highlight'
export function CodeBlock() {
const block = createHighlightedCodeBlockProps({
highlighter,
code: 'const answer = 42',
lang: 'ts',
})
return (
<pre>
<code dangerouslySetInnerHTML={{ __html: block.htmlMarkup }} />
</pre>
)
}
Correct:
import { createHighlightedCodeBlockProps } from '@tanstack/highlight/react'
import { highlighter } from './highlight'
export function CodeBlock() {
const block = createHighlightedCodeBlockProps({
highlighter,
code: 'const answer = 42',
lang: 'ts',
})
return <div dangerouslySetInnerHTML={{ __html: block.htmlMarkup }} />
}
htmlMarkup already contains the complete pre > code tree, so wrapping it creates invalid nested block markup.
Source: docs/guides/react.md
CRITICAL Inserting arbitrary HTML through block props
Wrong:
export function UserContent({ html }: { html: string }) {
return <div dangerouslySetInnerHTML={{ __html: html }} />
}
Correct:
import { createHighlightedCodeBlockProps } from '@tanstack/highlight/react'
import { highlighter } from './highlight'
export function UserCode({ code }: { code: string }) {
const block = createHighlightedCodeBlockProps({
highlighter,
code,
lang: 'plaintext',
})
return <div dangerouslySetInnerHTML={{ __html: block.htmlMarkup }} />
}
The highlighter escapes code source; the insertion prop does not sanitize unrelated HTML.
Source: docs/guides/react.md
HIGH Rehighlighting initial DOM during hydration
Wrong:
import { highlighter } from './highlight'
import { useEffect } from 'react'
export function HydratedCode() {
useEffect(() => {
document.querySelectorAll('pre code').forEach((node) => {
const pre = node.parentElement
const language = [...node.classList]
.find((name) => name.startsWith('language-'))
?.slice('language-'.length)
if (pre) {
pre.outerHTML = highlighter.highlightToHtml(node.textContent || '', {
lang: language,
})
}
})
}, [])
return null
}
Correct:
import type { HighlightedCodeBlockProps } from '@tanstack/highlight/react'
export function HydratedCode({ htmlMarkup }: HighlightedCodeBlockProps) {
return <div dangerouslySetInnerHTML={{ __html: htmlMarkup }} />
}
Server-rendered highlighted HTML is static and does not need a hydration effect.
Source: docs/guides/ssr-and-client.md
HIGH Passing a bare transformer to Octane
Wrong:
import { rehypeHighlightCodeBlocks } from '@tanstack/highlight/rehype'
import { highlighter } from './src/highlight'
export const rehypePlugins = [
rehypeHighlightCodeBlocks({ highlighter }),
]
Correct:
import { createOctaneMdxHighlight } from '@tanstack/highlight/octane'
import { highlighter } from './src/highlight'
export const rehypePlugins = [
createOctaneMdxHighlight({ highlighter }),
]
Octane MDX consumes the plugin-and-options tuple returned by its adapter.
Source: docs/guides/octane.md
CRITICAL Diverging server and client registries
Wrong:
import { createHighlighter } from '@tanstack/highlight/core'
import { html } from '@tanstack/highlight/languages/html'
import { js } from '@tanstack/highlight/languages/js'
const languages = typeof window === 'undefined' ? [html, js] : [html]
export const highlighter = createHighlighter({ languages })
Correct:
import { createHighlighter } from '@tanstack/highlight/core'
import { html } from '@tanstack/highlight/languages/html'
import { js } from '@tanstack/highlight/languages/js'
export const highlighter = createHighlighter({ languages: [html, js] })
Different registrations change normalized languages and embedded output during hydration.
Source: docs/guides/ssr-and-client.md
CRITICAL Mixing exact and block-normalized APIs
Wrong:
import { createHighlightedCodeBlockProps } from '@tanstack/highlight/react'
import { highlighter } from './highlight'
export const serverHtml = highlighter.highlightToHtml('const value = 1\n', {
lang: 'ts',
})
export const clientHtml = createHighlightedCodeBlockProps({
highlighter,
code: 'const value = 1\n',
lang: 'ts',
}).htmlMarkup
Correct:
import { createHighlightedCodeBlockProps } from '@tanstack/highlight/react'
import { highlighter } from './highlight'
export const serverHtml = createHighlightedCodeBlockProps({
highlighter,
code: 'const value = 1\n',
lang: 'ts',
}).htmlMarkup
export const clientHtml = createHighlightedCodeBlockProps({
highlighter,
code: 'const value = 1\n',
lang: 'ts',
}).htmlMarkup
Block-data adapters trim trailing whitespace while core highlight() preserves it.
Source: docs/guides/ssr-and-client.md
HIGH Tension: convenience versus client size
Adapters accept an explicit highlighter so the application controls retained languages. Passing root helpers around defeats that boundary.
See also: configure-selective-highlighting/SKILL.md - build one selective isomorphic registry.
HIGH Tension: structured output versus raw HTML
Use structured HAST in MDX pipelines. Insert generated htmlMarkup only inside an application-owned direct component.
See also: integrate-markdown-pipelines/SKILL.md - Remark and Rehype can avoid raw HTML.
HIGH Tension: exact source versus block normalization
Use the same adapter and options for server and client output. Theme selection does not affect markup, but source normalization does.
See also: integrate-markdown-pipelines/SKILL.md - fence helpers share block normalization.
References
See also: configure-selective-highlighting/SKILL.md - SSR and client output require the same registry and package version.
More skills from the highlight repository
View all 5 skillsconfigure-selective-highlighting
configure selective code highlighting registries
Jul 26ConfigurationFrontendPerformanceextend-language-support
extend language support for code highlighting
Jul 26API DevelopmentEngineeringintegrate-markdown-pipelines
integrate Markdown code highlighting pipelines
Jul 26API DevelopmentFrontendMarkdowntheme-and-annotate-code
style and annotate code blocks
Jul 26CSSFrontendThemes
More from TanStack
View publisheraggregation
perform data aggregation in TanStack Table
table
Jul 26Data AnalysisFrontendTanStackapi-not-found
diagnose TanStack Table API errors
table
Jul 26DebuggingFrontendTanStackcell-selection
select rectangular cell ranges in tables
table
Jul 26Data AnalysisTanStackUI Componentsclient-vs-server
manage TanStack Table data pipelines
table
Jul 26Data PipelineFrontendPerformanceTanStackcolumn-faceting
build faceted filter UIs
table
Jul 26Data VisualizationFrontendTanStackcolumn-filtering
implement column filtering in TanStack Table
table
Jul 26Data AnalysisFrontendTanStack