Code

Code displays source text with Tree-sitter syntax highlighting. Use Markdown for documents or Diff for changed lines.

Availability#

Field Availability
Package @opentui/core
Core renderable CodeRenderable
React <code> (automatic)
Solid <code> (automatic)
Status Built in

Basic usage#

Renderable API#

import { CodeRenderable, createCliRenderer, SyntaxStyle, RGBA } from "@opentui/core"

const renderer = await createCliRenderer()

const syntaxStyle = SyntaxStyle.fromStyles({
  default: { fg: RGBA.defaultForeground() },
  keyword: { fg: RGBA.defaultForeground(), bold: true },
  string: { fg: RGBA.fromIndex(247) },
  comment: { fg: RGBA.fromIndex(244), italic: true },
})

const code = new CodeRenderable(renderer, {
  id: "code",
  content: `function hello() {
  // This is a comment
  const message = "Hello, world!"
  return message
}`,
  filetype: "javascript",
  syntaxStyle,
  width: 50,
  height: 10,
})

renderer.root.add(code)

Creating syntax styles#

Use SyntaxStyle.fromStyles() to define colors and attributes for syntax tokens:

import { SyntaxStyle, RGBA, parseColor } from "@opentui/core"

const syntaxStyle = SyntaxStyle.fromStyles({
  // Basic tokens
  keyword: { fg: RGBA.fromHex("#FF7B72"), bold: true },
  "keyword.import": { fg: RGBA.fromHex("#FF7B72"), bold: true },
  "keyword.operator": { fg: RGBA.fromHex("#FF7B72") },

  string: { fg: RGBA.fromHex("#A5D6FF") },
  comment: { fg: RGBA.fromHex("#8B949E"), italic: true },
  number: { fg: RGBA.fromHex("#79C0FF") },
  boolean: { fg: RGBA.fromHex("#79C0FF") },
  constant: { fg: RGBA.fromHex("#79C0FF") },

  // Functions and types
  function: { fg: RGBA.fromHex("#D2A8FF") },
  "function.call": { fg: RGBA.fromHex("#D2A8FF") },
  "function.method.call": { fg: RGBA.fromHex("#D2A8FF") },
  type: { fg: RGBA.fromHex("#FFA657") },
  constructor: { fg: RGBA.fromHex("#FFA657") },

  // Variables and properties
  variable: { fg: RGBA.fromHex("#E6EDF3") },
  "variable.member": { fg: RGBA.fromHex("#79C0FF") },
  property: { fg: RGBA.fromHex("#79C0FF") },

  // Operators and punctuation
  operator: { fg: RGBA.fromHex("#FF7B72") },
  punctuation: { fg: RGBA.fromHex("#F0F6FC") },
  "punctuation.bracket": { fg: RGBA.fromHex("#F0F6FC") },
  "punctuation.delimiter": { fg: RGBA.fromHex("#C9D1D9") },

  // Default fallback
  default: { fg: RGBA.fromHex("#E6EDF3") },
})

Style properties#

Each style definition can include:

Property Type Description
fg RGBA Foreground (text) color
bg RGBA Background color
bold boolean Bold text
italic boolean Italic text
underline boolean Underlined text
dim boolean Dimmed text

Supported languages#

OpenTUI bundles Tree-sitter parsers for these languages:

  • JavaScript and JSX
  • TypeScript and TSX
  • Markdown and Markdown inline
  • Zig

Other grammars require configuration. See the Tree-sitter reference.

Streaming mode#

Enable streaming mode when content arrives incrementally, like LLM output:

const code = new CodeRenderable(renderer, {
  id: "streaming-code",
  content: "",
  filetype: "typescript",
  syntaxStyle,
  streaming: true, // Enable streaming mode
})

// Later, append content
code.content += "const x = 1\n"
code.content += "const y = 2\n"

Streaming mode changes intermediate rendering behavior during repeated updates. In particular, when drawUnstyledText is false, later updates keep the previous rendered buffer visible while a new one-shot highlight completes. Each highlight still processes the complete current content.

Text selection#

Text selection is enabled by default. Set selectable: false to disable it. Use selectionBg and selectionFg to customize selection colors:

const code = new CodeRenderable(renderer, {
  id: "code",
  content: sourceCode,
  filetype: "typescript",
  syntaxStyle,
  selectable: true,
  selectionBg: "#264F78",
  selectionFg: "#FFFFFF",
})

Concealment#

The conceal option controls whether certain syntax elements (like markdown formatting characters) are hidden:

const code = new CodeRenderable(renderer, {
  id: "markdown",
  content: "# Heading\n**bold** text",
  filetype: "markdown",
  syntaxStyle,
  conceal: true, // Hide formatting characters
})

With line numbers#

Use LineNumberRenderable to add line numbers:

import { CodeRenderable, LineNumberRenderable, RGBA, ScrollBoxRenderable, SyntaxStyle } from "@opentui/core"

const sourceCode = "const answer = 42\nconsole.log(answer)\n"
const syntaxStyle = SyntaxStyle.fromStyles({
  default: { fg: RGBA.fromHex("#E6EDF3") },
})

const code = new CodeRenderable(renderer, {
  id: "code",
  content: sourceCode,
  filetype: "typescript",
  syntaxStyle,
  width: "100%",
})

const lineNumbers = new LineNumberRenderable(renderer, {
  id: "code-with-lines",
  target: code,
  minWidth: 3,
  paddingRight: 1,
  fg: "#6b7280",
  bg: "#161b22",
  width: "100%",
})

// Wrap in ScrollBox for scrolling
const scrollbox = new ScrollBoxRenderable(renderer, {
  id: "scrollbox",
  width: 60,
  height: 20,
})
scrollbox.add(lineNumbers)
renderer.root.add(scrollbox)

Properties#

Property Type Default Description
content string "" Source code to display
filetype string - Language for syntax highlighting
syntaxStyle SyntaxStyle required Syntax highlighting theme
streaming boolean false Preserve suitable intermediate rendering during repeated updates
conceal boolean true Hide concealed syntax elements
drawUnstyledText boolean true Show unstyled text while highlighting. Streaming limits this to the initial highlight
treeSitterClient TreeSitterClient - Custom Tree-sitter client instance

Inherited from TextBufferRenderable#

Property Type Default Description
fg string | RGBA - Default foreground color
bg string | RGBA - Background color
selectable boolean true Whether text selection is enabled
selectionBg string | RGBA - Selection background color
selectionFg string | RGBA - Selection foreground color
wrapMode string "word" Text wrapping: "none", "char", "word"
textAlign "left" | "center" | "right" "left" Per-line alignment within the text width
tabIndicator string | number - Tab display character or width

Additional properties#

Property Type Description
lineCount number Number of lines in the current text buffer
scrollY number Current vertical scroll position (get/set)
scrollX number Current horizontal scroll position (get/set)
scrollWidth number Total scrollable width (read-only)
scrollHeight number Total scrollable height (read-only)
isHighlighting boolean Whether highlighting is in progress
plainText string Plain text in the current text buffer. It can differ from content after concealment or onChunks transforms

Markdown styles#

For markdown highlighting, use markup-prefixed style names:

const markdownStyle = SyntaxStyle.fromStyles({
  "markup.heading": { fg: RGBA.fromHex("#58A6FF"), bold: true },
  "markup.heading.1": { fg: RGBA.fromHex("#00FF88"), bold: true, underline: true },
  "markup.heading.2": { fg: RGBA.fromHex("#00D7FF"), bold: true },
  "markup.bold": { fg: RGBA.fromHex("#F0F6FC"), bold: true },
  "markup.strong": { fg: RGBA.fromHex("#F0F6FC"), bold: true },
  "markup.italic": { fg: RGBA.fromHex("#F0F6FC"), italic: true },
  "markup.list": { fg: RGBA.fromHex("#FF7B72") },
  "markup.quote": { fg: RGBA.fromHex("#8B949E"), italic: true },
  "markup.raw": { fg: RGBA.fromHex("#A5D6FF") },
  "markup.raw.block": { fg: RGBA.fromHex("#A5D6FF") },
  "markup.link": { fg: RGBA.fromHex("#58A6FF"), underline: true },
  "markup.link.url": { fg: RGBA.fromHex("#58A6FF"), underline: true },
  default: { fg: RGBA.fromHex("#E6EDF3") },
})

Use Markdown for document structure and fenced code. Add a Line number gutter to a code renderable. Use Diff for unified or split patches. Use TextTable for tabular content without syntax parsing.

Read Text and terminal cells for wrapping, graphemes, and display-cell widths.