Skip to main content

Starlighter

Python Version PyPI Version License Zero Dependencies

Server-side Python syntax highlighter with zero dependencies. Built for StarHTML with Datastar-aware tokenization, and compatible with FastHTML.

Features

  • Fast: ~1.5ms P99 for 200-line files, ~3ms for 500-line files
  • XSS-safe: All output is entity-encoded
  • Zero dependencies: Pure Python standard library
  • 17 built-in themes: GitHub, VS Code, Monokai, Catppuccin, Dracula, Nord, Solarized, One Dark, Xcode (dark + light variants)
  • StarHTML-aware: Distinct token classes for HTML elements, Datastar attributes, signals, and CSS class/style strings
  • FastHTML compatible: Works with both StarHTML and FastHTML projects

Installation

# Using uv (recommended)
uv add starlighter

# Using pip
pip install starlighter

Usage

Basic highlighting

from starlighter import highlight

code = '''def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10))'''

html = highlight(code)

StarHTML-aware highlighting

The lexer recognizes StarHTML elements, Datastar attributes, and signal references, giving each a distinct token class:

from starlighter import highlight

code = '''Button(
    "Increment",
    data_on_click=count.add(1),
    cls="px-4 py-2 bg-blue-500"
)'''

html = highlight(code)
# Button  -> token-starhtml-element
# data_on_click -> token-datastar-attr
# cls string    -> token-css-class

You can also register custom elements, attributes, and signal names:

html = highlight(
    code,
    elements={"MyWidget", "AppShell"},
    attrs={"custom_bind"},
    signals={"count", "message"},
)

With StarHTML

from starhtml import *
from starlighter import CodeBlock, StarlighterStyles

app, rt = star_app(
    hdrs=(
        StarlighterStyles("github-dark", "monokai", "dracula"),
    )
)

@rt("/")
def home():
    sample = '''def greet(name: str) -> str:
    return f"Hello, {name}!"'''

    return Div(
        H1("Code Preview"),
        CodeBlock(sample, theme="github-dark"),
        cls="container"
    )

serve()

With FastHTML

from fasthtml.common import *
from starlighter import CodeBlock, StarlighterStyles

app, rt = fast_app(
    pico=False,
    hdrs=(StarlighterStyles("vscode"),)
)

@rt("/")
def get():
    return Div(
        CodeBlock('print("hello")', theme="vscode"),
        cls="container"
    )

serve()

Themes

17 themes are available:

Dark Light
github-dark (default) github-light
vscode-dark / vscode vscode-light
monokai catppuccin-latte
catppuccin-mocha nord-light
dracula solarized-light
one-dark xcode-light
nord-dark
solarized-dark
xcode-dark
from starlighter import get_theme_css

# Get raw CSS for a theme
css = get_theme_css("monokai")

# Use StarlighterStyles to load multiple themes at once
StarlighterStyles("github-dark", "monokai", "dracula")

# Auto-switch between themes based on prefers-color-scheme
StarlighterStyles("github-dark", "github-light", auto_switch=True)

CSS Token Classes

Class Tokens
.token-keyword def, class, if, for, return, ...
.token-string "text", 'text', f"..."
.token-comment # ..., docstrings
.token-number 42, 3.14, 0xFF
.token-operator +, -, ==, !=
.token-identifier Variable and function names
.token-builtin print, len, str, range, ...
.token-decorator @app.route, @property
.token-punctuation (), [], {}, ,, :
.token-starhtml-element Div, Button, Input, ...
.token-datastar-attr data_on_click, data_bind, ...
.token-signal Signal variable references
.token-css-class Strings passed to cls=, data_class=
.token-css-style Strings passed to style=, data_style=

API

from starlighter import highlight, CodeBlock, StarlighterStyles, get_theme_css

highlight(
    code: str,
    language: str | None = "python",
    elements: set[str] | None = None,
    attrs: set[str] | None = None,
    signals: set[str] | None = None,
) -> str

CodeBlock(code: str, theme: str = "github-dark", **kwargs) -> Component

StarlighterStyles(*themes: str, auto_switch: bool = False, **kwargs) -> Style

get_theme_css(theme: str = "github-dark") -> str

Security

All input is HTML-entity-encoded before output. Script injection via code input is not possible:

code = 'return "</pre><script>alert(1)</script><pre>"'
html = highlight(code)
# Scripts are escaped: &lt;script&gt;alert(1)&lt;/script&gt;

Development

git clone https://github.com/banditburai/starlighter.git
cd starlighter
uv sync --all-extras
uv run pytest tests/ -v --cov=starlighter
uv run ruff check && uv run ruff format --check

Metadata

Release files for starlighter 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for starlighter 0.2.0
File Size Uploaded
starlighter-0.2.0.tar.gz 10.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for starlighter 0.2.0
File Interpreter ABI Platform
starlighter-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 22.9 kB

Release files / starlighter-0.2.0.tar.gz

Download URL starlighter-0.2.0.tar.gz
Size 10.9 kB
Tags Source
SHA-256 checksum
How to use checksums
e74134ce1e38ef27b181c09e138021e327024d8fbe8d1054048962323540e04f
BLAKE2b-256 checksum
How to use checksums
ecb66b93e2a82094f5b483dfa6140dc5feb61d0e4630a41f0d85295d7bfcb653
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 28, 2026.

Transparency log

Release files / starlighter-0.2.0-py3-none-any.whl

Download URL starlighter-0.2.0-py3-none-any.whl
Size 11.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
faab3babc81eb6b33bac4e86ded536e5381b87554497cafebe142b4b98264ce3
BLAKE2b-256 checksum
How to use checksums
697cecc8a9bce5737c4668f6e4963a114e610bb5b413a452133e7ce0032ff437
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 28, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page