Skip to content

JSX/TSX Support

ts-syntax-highlighter provides complete support for JSX and TSX, making it ideal for React and other JSX-based frameworks.

What is JSX/TSX?

JSX (JavaScript XML) is a syntax extension for JavaScript that allows you to write HTML-like code in JavaScript files. It's commonly used with React.

TSX (TypeScript XML) is JSX with TypeScript type annotations, combining the benefits of both technologies.

Basic JSX

Simple Elements

jsx
// Basic element
const element = <div>Hello World</div>

// With attributes
const button = <button className="primary">Click me</button>

// Self-closing
const image = <img src="photo.jpg" alt="Photo" />

// Multiple attributes
const input = (
  <input
    type="text"
    placeholder="Enter name"
    value={value}
    onChange={handleChange}
  />
)

JSX Expressions

Embed JavaScript expressions using curly braces:

jsx
// Variables
const greeting = <h1>Hello, {name}!</h1>

// Function calls
const result = <div>{calculate(x, y)}</div>

// Expressions
const math = <span>{a + b}</span>

// Ternary operators
const message = (
  <div>
    {isLoggedIn ? <WelcomeMessage /> : <LoginPrompt />}
  </div>
)

// Logical AND
const alert = (
  <div>
    {hasError && <ErrorMessage />}
  </div>
)

Nested JSX

jsx
const card = (
  <div className="card">
    <header className="card-header">
      <h2>{title}</h2>
      <button onClick={onClose}>×</button>
    </header>
    <main className="card-body">
      {children}
    </main>
    <footer className="card-footer">
      <button onClick={onSave}>Save</button>
      <button onClick={onCancel}>Cancel</button>
    </footer>
  </div>
)

JSX Components

Function Components

jsx
function Welcome({ name }) {
  return <h1>Hello, {name}!</h1>
}

const App = () => {
  return (
    <div>
      <Welcome name="Alice" />
      <Welcome name="Bob" />
    </div>
  )
}

Component Composition

jsx
const Layout = ({ children }) => (
  <div className="layout">
    <Header />
    <Sidebar />
    <main>{children}</main>
    <Footer />
  </div>
)

const App = () => (
  <Layout>
    <Dashboard />
  </Layout>
)

Props Spreading

jsx
const button = <Button {...props} />

const input = (
  <Input
    {...commonProps}
    type="text"
    placeholder="Override"
  />
)

TypeScript JSX (TSX)

Typed Components

typescript
interface ButtonProps {
  variant: 'primary' | 'secondary'
  onClick: () => void
  disabled?: boolean
  children: React.ReactNode
}

const Button: React.FC<ButtonProps> = ({
  variant,
  onClick,
  disabled = false,
  children
}) => {
  return (
    <button
      className={`btn btn-${variant}`}
      onClick={onClick}
      disabled={disabled}
    >
      {children}
    </button>
  )
}

Generic Components

typescript
interface ListProps<T> {
  items: T[]
  renderItem: (item: T) => React.ReactNode
}

function List<T>({ items, renderItem }: ListProps<T>) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{renderItem(item)}</li>
      ))}
    </ul>
  )
}

// Usage
const users = <List<User> items={users} renderItem={user => user.name} />

Type Assertions in TSX

typescript
const component = <Button<string> onClick={handler} />

const element = (
  <Component
    {...(props as ComponentProps)}
  />
)

Typed Event Handlers

typescript
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
  console.log(event.currentTarget)
}

const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
  setValue(event.target.value)
}

const form = (
  <form>
    <button onClick={handleClick}>Click</button>
    <input onChange={handleChange} />
  </form>
)

Advanced JSX Patterns

Fragments

jsx
// Long form
const list = (
  <React.Fragment>
    <li>Item 1</li>
    <li>Item 2</li>
  </React.Fragment>
)

// Short form
const list = (
  <>
    <li>Item 1</li>
    <li>Item 2</li>
  </>
)

// With key
const list = items.map(item => (
  <React.Fragment key={item.id}>
    <dt>{item.term}</dt>
    <dd>{item.definition}</dd>
  </React.Fragment>
))

Conditional Rendering

jsx
// Ternary
const message = isLoggedIn ? <Welcome /> : <Login />

// Logical AND
const alert = hasError && <ErrorAlert />

// Nullish coalescing
const value = data ?? <Loading />

// Switch-like with object
const views = {
  home: <Home />,
  about: <About />,
  contact: <Contact />
}
const view = views[currentView]

Lists and Keys

jsx
const users = userList.map(user => (
  <UserCard
    key={user.id}
    name={user.name}
    email={user.email}
  />
))

const items = data.map((item, index) => (
  <li key={`${item.id}-${index}`}>
    {item.name}
  </li>
))

Children Patterns

jsx
// Render props
const DataProvider = ({ children }) => {
  const [data, setData] = useState(null)
  return children(data, setData)
}

<DataProvider>
  {(data, setData) => (
    <div>{data}</div>
  )}
</DataProvider>

// Children as function
const List = ({ items, children }) => (
  <ul>
    {items.map(item => (
      <li key={item.id}>{children(item)}</li>
    ))}
  </ul>
)

<List items={users}>
  {user => <UserCard user={user} />}
</List>

JSX with Frameworks

React

jsx
import React from 'react'

function App() {
  const [count, setCount] = React.useState(0)

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
    </div>
  )
}

Preact

jsx
import { h } from 'preact'
import { useState } from 'preact/hooks'

export function App() {
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
    </div>
  )
}

Solid

jsx
import { createSignal } from 'solid-js'

function App() {
  const [count, setCount] = createSignal(0)

  return (
    <div>
      <p>Count: {count()}</p>
      <button onClick={() => setCount(count() + 1)}>
        Increment
      </button>
    </div>
  )
}

Highlighting Features

Accurate Tag Detection

jsx
// Opening tags
<div>
<Component>
<custom-element>

// Self-closing tags
<img />
<Component />
<input />

// Closing tags
</div>
</Component>
</custom-element>

Attribute Highlighting

jsx
<Component
  // Standard attributes
  className="container"
  id="main"

  // Data attributes
  data-testid="component"

  // Aria attributes
  aria-label="Description"

  // Custom attributes
  customProp="value"

  // Boolean attributes
  disabled
  required

  // Event handlers
  onClick={handler}
  onChange={handleChange}
/>

Expression Detection

jsx
// Simple expressions
<div>{value}</div>

// Complex expressions
<div>{calculate(a, b, c)}</div>

// Nested JSX in expressions
<div>
  {items.map(item => (
    <Item key={item.id} {...item} />
  ))}
</div>

// Spread in JSX
<Component {...props} />

Component vs. HTML Element

jsx
// HTML elements (lowercase)
<div></div>
<span></span>
<button></button>

// Components (PascalCase)
<MyComponent />
<UserCard />
<Button />

// Custom elements (kebab-case)
<my-element></my-element>
<custom-button></custom-button>

Common Patterns

Conditional Classes

jsx
const button = (
  <button
    className={`btn ${isPrimary ? 'btn-primary' : 'btn-secondary'} ${
      isDisabled ? 'disabled' : ''
    }`}
  >
    Click me
  </button>
)

// With classnames library
import classNames from 'classnames'

const button = (
  <button
    className={classNames('btn', {
      'btn-primary': isPrimary,
      'btn-secondary': !isPrimary,
      'disabled': isDisabled
    })}
  >
    Click me
  </button>
)

Inline Styles

jsx
const element = (
  <div
    style={{
      color: 'red',
      fontSize: '16px',
      backgroundColor: isActive ? 'blue' : 'gray'
    }}
  >
    Styled content
  </div>
)

Refs

jsx
const inputRef = React.useRef<HTMLInputElement>(null)

const form = (
  <form>
    <input ref={inputRef} type="text" />
    <button onClick={() => inputRef.current?.focus()}>
      Focus Input
    </button>
  </form>
)

Performance

JSX/TSX tokenization is optimized for real-time highlighting:

typescript
const tokenizer = new Tokenizer('javascript') // or 'typescript'

// Fast JSX tokenization
const code = `
const App = () => (
  <div className="app">
    <Header />
    <Main>{children}</Main>
    <Footer />
  </div>
)
`

const tokens = await tokenizer.tokenizeAsync(code)
// ~0.05ms - Fast enough for real-time highlighting

Next Steps

Released under the MIT License.