logoassistant-ui

Syntax Highlighting

Syntax highlighting for code blocks in markdown.

Syntax highlighting is not enabled in markdown by default.

assistant-ui provides two options for syntax highlighting:

  • react-shiki (recommended for performance & dynamic language support)
  • react-syntax-highlighter (legacy - Prism or Highlight.js based)

react-shiki

Add shiki-highlighter

npx shadcn@latest add @assistant-ui/shiki-highlighter

Main Component

npm install react-shiki
yarn add react-shiki
pnpm add react-shiki
bun add react-shiki
xpm add react-shiki
"use client";import { FC } from "react";import ShikiHighlighter, { type ShikiHighlighterProps } from "react-shiki";import type { SyntaxHighlighterProps as AUIProps } from "@assistant-ui/react-markdown";import { cn } from "@/lib/utils";/** * Props for the SyntaxHighlighter component */export type HighlighterProps = Omit<  ShikiHighlighterProps,  "children" | "theme"> & {  theme?: ShikiHighlighterProps["theme"];} & Pick<AUIProps, "node" | "components" | "language" | "code">;/** * SyntaxHighlighter component, using react-shiki * Use it by passing to `defaultComponents` in `markdown-text.tsx` * * @example * const defaultComponents = memoizeMarkdownComponents({ *   SyntaxHighlighter, *   h1: //... *   //...other elements... * }); */export const SyntaxHighlighter: FC<HighlighterProps> = ({  code,  language,  theme = { dark: "kanagawa-wave", light: "kanagawa-lotus" },  className,  addDefaultStyles = false, // assistant-ui requires custom base styles  showLanguage = false, // assistant-ui/react-markdown handles language labels  node: _node,  components: _components,  ...props}) => {  return (    <ShikiHighlighter      {...props}      language={language}      theme={theme}      addDefaultStyles={addDefaultStyles}      showLanguage={showLanguage}      defaultColor="light-dark()"      className={cn(        "aui-shiki-base [&_pre]:overflow-x-auto [&_pre]:rounded-b-lg [&_pre]:bg-muted/75! [&_pre]:p-4",        className,      )}    >      {code.trim()}    </ShikiHighlighter>  );};SyntaxHighlighter.displayName = "SyntaxHighlighter";

This adds a /components/assistant-ui/shiki-highlighter.tsx file to your project and installs the react-shiki dependency. The highlighter can be customized by editing the config in the shiki-highlighter.tsx file.

Add it to defaultComponents in markdown-text.tsx

/components/assistant-ui/markdown-text.tsx
import { SyntaxHighlighter } from "./shiki-highlighter";

export const defaultComponents = memoizeMarkdownComponents({
  SyntaxHighlighter: SyntaxHighlighter,
  h1: /* ... */,
  // ...other elements...
});

Options

Prop

Type

Bundle Optimization

By default, react-shiki includes the full Shiki bundle, which contains all supported languages and themes.

To reduce bundle size, you can use the web bundle by changing the import to react-shiki/web, to include a smaller bundle of web related languages:

/components/assistant-ui/shiki-highlighter.tsx
import ShikiHighlighter, { type ShikiHighlighterProps } from "react-shiki/web";

Custom Bundles

For strict bundle size control, react-shiki also supports custom bundles created using createHighlighterCore from react-shiki/core (re-exported from Shiki):

/components/assistant-ui/shiki-highlighter.tsx
import { createHighlighterCore, createOnigurumaEngine } from "react-shiki/core";

// Create the highlighter
// Use dynamic imports to load languages and themes on client on demand
const customHighlighter = await createHighlighterCore({
  themes: [import("@shikijs/themes/nord")],
  langs: [
    import("@shikijs/langs/javascript"),
    import("@shikijs/langs/typescript"),
  ],
  engine: createOnigurumaEngine(import("shiki/wasm")), 
});

// Then pass it to the highlighter prop
<SyntaxHighlighter
  {...props}
  language={language}
  theme={theme}
  highlighter={customHighlighter}
/>;

For more information, see react-shiki - bundle options.

Dual/multi theme support

To use multiple theme modes, pass an object with your multi-theme configuration to the theme prop in the ShikiHighlighter component:

/components/assistant-ui/shiki-highlighter.tsx
<ShikiHighlighter
  /* ... */
  theme={{
    light: "github-light",
    dark: "github-dark",
  }}
  /* ... */
>

To make themes responsive to your site's theme mode, add one of the following CSS snippets to your project:

shiki.css
/* for class based dark mode */
html.dark .shiki,
html.dark .shiki span {
  color: var(--shiki-dark) !important;
  background-color: var(--shiki-dark-bg) !important;
  /* Optional, if you also want font styles */
  font-style: var(--shiki-dark-font-style) !important;
  font-weight: var(--shiki-dark-font-weight) !important;
  text-decoration: var(--shiki-dark-text-decoration) !important;
}

/* for query based dark mode */
@media (prefers-color-scheme: dark) {
  .shiki,
  .shiki span {
    color: var(--shiki-dark) !important;
    background-color: var(--shiki-dark-bg) !important;
    /* Optional, if you also want font styles */
    font-style: var(--shiki-dark-font-style) !important;
    font-weight: var(--shiki-dark-font-weight) !important;
    text-decoration: var(--shiki-dark-text-decoration) !important;
  }
}

For more information, see Shiki's documentation on dual and multi themes.


react-syntax-highlighter

This option may be removed in a future release. Consider using react-shiki instead.

Add syntax-highlighter

npx shadcn@latest add @assistant-ui/syntax-highlighter

Main Component

npm install @assistant-ui/react-syntax-highlighter @types/react-syntax-highlighter react-syntax-highlighter
yarn add @assistant-ui/react-syntax-highlighter @types/react-syntax-highlighter react-syntax-highlighter
pnpm add @assistant-ui/react-syntax-highlighter @types/react-syntax-highlighter react-syntax-highlighter
bun add @assistant-ui/react-syntax-highlighter @types/react-syntax-highlighter react-syntax-highlighter
xpm add @assistant-ui/react-syntax-highlighter @types/react-syntax-highlighter react-syntax-highlighter
import { PrismAsyncLight } from "react-syntax-highlighter";import { makePrismAsyncLightSyntaxHighlighter } from "@assistant-ui/react-syntax-highlighter";import tsx from "react-syntax-highlighter/dist/esm/languages/prism/tsx";import python from "react-syntax-highlighter/dist/esm/languages/prism/python";import { coldarkDark } from "react-syntax-highlighter/dist/cjs/styles/prism";// register languages you want to supportPrismAsyncLight.registerLanguage("js", tsx);PrismAsyncLight.registerLanguage("jsx", tsx);PrismAsyncLight.registerLanguage("ts", tsx);PrismAsyncLight.registerLanguage("tsx", tsx);PrismAsyncLight.registerLanguage("python", python);export const SyntaxHighlighter = makePrismAsyncLightSyntaxHighlighter({  style: coldarkDark,  customStyle: {    margin: 0,    width: "100%",    background: "black",    padding: "1.5rem 1rem",  },});

Adds a /components/assistant-ui/syntax-highlighter.tsx file to your project and installs the react-syntax-highlighter dependency.

Add it to defaultComponents in markdown-text.tsx

/components/assistant-ui/markdown-text.tsx
import { SyntaxHighlighter } from "./syntax-highlighter";

export const defaultComponents = memoizeMarkdownComponents({
  SyntaxHighlighter: SyntaxHighlighter,
  h1: /* ... */,
  // ...other elements...
});

Options

Supports all options from react-syntax-highlighter.

Bundle Optimization

By default, the syntax highlighter uses a light build that only includes languages you register. To include all languages:

/components/assistant-ui/syntax-highlighter.tsx
import { makePrismAsyncSyntaxHighlighter } from "@assistant-ui/react-syntax-highlighter/full";

On this page

Edit on GitHub