Getting started
Theming
Light and dark are built in. Everything else — accent, radius, type — is a CSS custom property away.
Light and dark #
Light is the default. Put class="dark" or data-theme="dark" on any ancestor — usually <html> — and everything below switches. Themes can be scoped, too:
<section data-theme="dark">
<!-- Everything in here renders dark, whatever the page uses. -->
</section>Dark mode isn’t an inversion. Surfaces step up in lightness as they rise (page → surface → raised), borders carry more of the structure, and shadows get deeper to stay visible.
Avoid the flash #
To render the right theme on first paint, set the class from an inline script in <head> before the page draws. This site does exactly that:
// nuxt.config.ts — set the class before first paint
const themeScript = `(function(){try{
var t = localStorage.getItem('theme') || 'system';
var dark = t === 'dark' || (t === 'system' && matchMedia('(prefers-color-scheme: dark)').matches);
document.documentElement.classList.toggle('dark', dark);
}catch(e){}})()`
export default defineNuxtConfig({
app: {
head: { script: [{ innerHTML: themeScript, tagPosition: 'head' }] },
},
})Customising #
Every visual decision is a token prefixed with --juxt-. Override them after juxt.ui’s stylesheet, globally or on any subtree. Components read tokens at runtime, so there is nothing to rebuild.
:root {
/* A warmer accent */
--juxt-accent: #0e8f76;
--juxt-accent-hover: #0c7c66;
--juxt-accent-text: #0a6b58;
--juxt-ring: rgb(14 143 118 / 0.55);
--juxt-ring-soft: rgb(14 143 118 / 0.16);
/* Slightly rounder controls */
--juxt-radius-sm: 0.5rem;
--juxt-radius-md: 0.625rem;
}
.dark {
--juxt-accent-text: #2fcfa9;
} When you change the accent, change its -text variant too: it is tuned separately per theme so text stays above WCAG AA contrast on both backgrounds.
See Design tokens for the full list.