Technical previewShare feedback

Escaping to Override Components

Updated Nov 12, 2026

Livemark ships a library of React components, shadcn-style primitives, and a base stylesheet. Each file can be overridden by placing a same-named file under .livemark/:

To overrideDrop a file at
source/components/<Name>.tsx.livemark/components/<Name>.tsx
source/elements/<name>.tsx.livemark/elements/<name>.tsx
source/styles/<name>.css.livemark/styles/<name>.css
source/routes/<route>.tsx.livemark/routes/<route>.tsx
source/client.tsx, server.ts, router.tsx, head.ts.livemark/<same name>

A Markdown directive renders the component named after it: :::card is components/Card.tsx, ::video is components/Video.tsx, and a group of cards is components/Cards.tsx. The note, tip, info, warning and danger callouts all render components/Callout.tsx.

The source/ paths are inside node_modules/livemark/, or node_modules/@livemark/markdown/ for the components, elements and styles that render Markdown; livemark escape --list shows both. Files under .livemark/public/ are added to the site's static assets and served from its root.

No import changes are needed. The rest of Livemark picks up the overridden file automatically.

The livemark escape command

Finding and copying a default file to override is automated:

# Pick files from a searchable list:
livemark escape

# Print every overridable file:
livemark escape --list

# Copy specific defaults into .livemark/:
livemark escape components/Footer.tsx elements/button.tsx

In a terminal, livemark escape opens a picker: type to filter, Tab to select, Enter to copy. Files you already override are shown but can't be picked. Outside a terminal (a pipe, CI) it prints the list, as --list does.

livemark escape refuses to overwrite an existing file. Delete the override first if you want to start over.

Deleting an override restores the default — at once while the dev server runs, otherwise on the next start or build.

livemark escape components/Footer.tsx

Then edit .livemark/components/Footer.tsx:

.livemark/components/Footer.tsx
export function Footer() {
  return (
    <p className="mt-12 text-center text-sm text-muted-foreground">
      Built by my team · 2026
    </p>
  )
}

Save — the dev server picks it up immediately.

Example: retheme buttons

livemark escape elements/button.tsx

Edit the cva class list in .livemark/elements/button.tsx to change button styling globally. Because every Livemark-shipped component imports its Button through the override system, your variant applies everywhere.

Example: tweak a token

livemark escape styles/general.css

Edit the :root block in .livemark/styles/general.css to rebrand:

:root {
  --primary: oklch(0.55 0.24 27); /* red */
}

Importing other Livemark modules from an override

Inside an override, import other Livemark modules from the livemark/<subdir>/* subpath exports:

.livemark/components/Footer.tsx
import { cn } from "cn"
import { Button } from "livemark/elements/button"

Those paths resolve at build time and go through the same override lookup — if you've also overridden button, your override wins there too.

Type checking overrides

An escaped file keeps the relative imports of the default it was copied from (../hooks/site.ts). Those resolve inside the mount Livemark generates for start and build, not next to .livemark/, so your project's own tsc --noEmit cannot check an escaped file — leave .livemark/ out of its program. livemark build is what verifies an override: it bundles it with the rest of Livemark and fails when an import does not resolve.

A file you write yourself that imports only the livemark/<subdir>/* exports can be type-checked, including the livemark:virtual module the site config comes from. Its types load with the livemark package: any program that includes livemark.config.ts already has them. A program that doesn't adds one line to a .d.ts file:

.livemark/env.d.ts
/// <reference types="livemark/env" />

Don't declare livemark:virtual yourself: a hand-written declaration drifts from the real config type.

What you can't override this way

  • New pages — these are custom routes, added under the same .livemark/routes/ folder.
  • Server code (actions/, commands/) — not overridable; fork the repo if you need to change these.
  • Config schema — shape of livemark.config.ts is fixed.

See also

  • Syntax Themes — the lighter-weight knob if you only want to recolour code.
  • Custom Routes — authoring new pages (rather than replacing existing ones).

Created with ❤ and Livemark