Overview
Snapp supports runtime theming through a single CSS file that overrides the application’s design tokens.
There is no rebuild step, no Tailwind recompilation, and no component-level overrides.
Styling is applied by redefining CSS custom properties that Tailwind and the UI layer already consume.
How custom styling is loaded
Snapp injects a stylesheet at the very end of the HTML document.
<!-- Custom Style Override -->
<link rel="stylesheet" href="/custom.css" />
Because this link is placed after the entire application markup, all definitions inside custom.css take precedence via normal CSS cascade rules.
Where custom.css comes from
The /custom.css file is served by Snapp at runtime.
Internally, it is read from:
config/custom.css
This file is typically mounted via Docker.
Example volume mapping:
volumes:
- ./config/custom.css:/app/config/custom.css
Snapp exposes it through a dedicated endpoint with long-term caching:
Content-Type: text/cssCache-Control: max-age=31536000
No application restart is required to change styles; only the file content matters.
What you are expected to put in custom.css
You are expected to redefine only CSS variables, not write component CSS.
The recommended approach is:
- Generate a theme using a Shadcn-compatible theme generator (for example: https://www.shadcn.io/theme-generator)
- Copy only the
:root { ... }and.dark { ... }blocks - Paste them into
config/custom.css
Example structure:
:root {
--background: oklch(...);
--foreground: oklch(...);
--primary: oklch(...);
--radius: 0.25rem;
--font-sans: 'Lato', sans-serif;
/* … */
}
.dark {
--background: oklch(...);
--foreground: oklch(...);
/* … */
}
These variables directly replace the defaults shipped with Snapp.
Tailwind integration
Snapp uses Tailwind tokens that are mapped to CSS variables.
The mapping is defined once and reused everywhere:
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-primary: var(--primary);
--radius-lg: var(--radius);
/* … */
}
Because of this:
- All Tailwind utilities (
bg-background,text-foreground, etc.) update automatically - All UI components update automatically
- Charts, sidebar, modals, and forms stay consistent
No Tailwind config changes are required.
Fonts and typography
You can override fonts the same way, using CSS variables:
:root {
--font-sans: 'Lato', sans-serif;
--font-serif: 'Merriweather', serif;
--font-mono: 'Roboto Mono', monospace;
}
If you import fonts from Google Fonts or other providers, do it at the top of custom.css.
Dark mode
Dark mode is handled through the .dark selector.
Snapp toggles the dark class on the root element. Your responsibility is only to define the variables.
There is no JavaScript or theme switch logic to implement.
What this system does not allow
- No per-component CSS overrides
- No Tailwind rebuilds
- No runtime class injection
- No inline style mutation
Styling is declarative, global, and token-based by design.
If a value is not exposed as a CSS variable, it is not meant to be themed.