Essentials

Customize themes and styles in Lapikit

Theme customization

Lapikit is built on custom CSS properties. Colors, surfaces, spacing, radii, typography, and component states are all based on --kit-* variables.

This makes the design system predictable, easy to evolve, and simple to customize without modifying component logic or adding extensions.

Default theme configuration

Lapikit maintains a styling behavior similar to that of native CSS.

Each component and theme value can be overridden directly using CSS variables. Here is a list of all the variables you can override:

// root
:global(html) {
	--kit-shape-none: 0;
	--kit-shape-xs: 4px;
	--kit-shape-sm: 6px;
	--kit-shape-md: 10px;
	--kit-shape-lg: 14px;
	--kit-shape-xl: 18px;
	--kit-shape-full: 9999px;

	--kit-font-xs: 13px;
	--kit-font-sm: 14px;
	--kit-font-md: 15px;
	--kit-font-lg: 16px;
	--kit-font-xl: 17px;

	--kit-space-compact: 2px;
	--kit-space-default: 4px;
	--kit-space-comfortable: 6px;

	--kit-density-compact: -4px;
	--kit-density-default: 0px;
	--kit-density-comfortable: 4px;

	--kit-shadow-opacity: 30%;
	--kit-shadow-ambient-opacity: 15%;

	--kit-disabled-opacity: 0.55;
	--kit-font:
		ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
		'Noto Color Emoji';
}


// theme
:global(html:not([data-kit-theme])) {
	--kit-color-surface: hsl(0 0% 100%);
	--kit-color-surface-1: hsl(240 15% 96.5%);
	--kit-color-surface-2: hsl(240 10% 93%);
	--kit-color-surface-3: hsl(0 0% 100%);

	--kit-color-text: hsl(222 20% 10%);
	--kit-color-text-muted: hsl(220 10% 40%);
	--kit-color-text-subtle: hsl(220 8% 58%);
	--kit-color-text-disabled: hsl(220 5% 76%);

	--kit-color-fill: hsl(240 8% 93%);
	--kit-color-fill-hover: hsl(240 4% 91%);
	--kit-color-fill-active: hsl(240 4% 88%);

	--kit-color-border: hsl(220 16% 88%);
	--kit-color-shadow: hsl(240 3% 11%);

	--kit-color-accent: hsl(220 90% 56%);
	--kit-color-on-accent: hsl(0 0% 100%);
	--kit-color-success: hsl(145 50% 38%);
	--kit-color-on-success: hsl(0 0% 100%);
	--kit-color-warning: hsl(35 80% 45%);
	--kit-color-on-warning: hsl(222 20% 10%);
	--kit-color-error: hsl(5 65% 48%);
	--kit-color-on-error: hsl(0 0% 100%);
	--kit-color-info: hsl(205 60% 42%);
	--kit-color-on-info: hsl(0 0% 100%);
	--kit-color-focus: hsl(35 90% 56%);

	--kit-color-transparent: transparent;
}

No additional compilation steps are required.

You can apply your own values directly in your stylesheet and integrate Lapikit into an existing design system without having to rewrite the components.

style.css
:root {
	--kit-accent: hsl(262 80% 50%);
	--kit-radius-1: 4px;
	--kit-radius-2: 8px;
	--kit-font: 'Inter', sans-serif;
}

Theme mode support

Lapikit resolves its color tokens through the data-kit-theme attribute. Set it to light or dark on the element you want to theme usually <html>, but any container works. Because it’s a plain attribute, you keep full control: toggle it from your own logic, persist the choice, or scope a dark section inside an otherwise light page with function useTheme().

// dark
:global([data-kit-theme='dark']) {
	color-scheme: dark;

	--kit-color-surface: hsl(240 3% 11%);
	--kit-color-surface-1: hsl(240 2% 17.5%);
	--kit-color-surface-2: hsl(240 1.5% 23%);
	--kit-color-surface-3: hsl(240 1.5% 28%);

	--kit-color-text: hsl(0 0% 100%);
	--kit-color-text-muted: hsl(240 3% 56%);
	--kit-color-text-subtle: hsl(240 2.5% 38%);
	--kit-color-text-disabled: hsl(240 1.5% 25%);

	--kit-color-fill: hsl(240 2.5% 24%);
	--kit-color-fill-hover: hsl(240 2.5% 28%);
	--kit-color-fill-active: hsl(240 2.5% 31%);

	--kit-color-border: hsl(240 2% 26%);
	--kit-color-shadow: hsl(240 3% 11%);

	--kit-color-accent: hsl(220 85% 65%);
	--kit-color-on-accent: hsl(240 3% 11%);
	--kit-color-success: hsl(145 50% 50%);
	--kit-color-on-success: hsl(240 3% 11%);
	--kit-color-warning: hsl(35 85% 58%);
	--kit-color-on-warning: hsl(240 3% 11%);
	--kit-color-error: hsl(5 70% 60%);
	--kit-color-on-error: hsl(240 3% 11%);
	--kit-color-info: hsl(205 65% 58%);
	--kit-color-on-info: hsl(240 3% 11%);
	--kit-color-focus: hsl(35 90% 62%);
}


// light
:global([data-kit-theme='light']) {
	color-scheme: light;
	--kit-color-surface: hsl(0 0% 100%);
	--kit-color-surface-1: hsl(240 15% 96.5%);
	--kit-color-surface-2: hsl(240 10% 93%);
	--kit-color-surface-3: hsl(0 0% 100%);

	--kit-color-text: hsl(222 20% 10%);
	--kit-color-text-muted: hsl(220 10% 40%);
	--kit-color-text-subtle: hsl(220 8% 58%);
	--kit-color-text-disabled: hsl(220 5% 76%);

	--kit-color-fill: hsl(240 8% 93%);
	--kit-color-fill-hover: hsl(240 4% 91%);
	--kit-color-fill-active: hsl(240 4% 88%);

	--kit-color-border: hsl(220 16% 88%);
	--kit-color-shadow: hsl(240 3% 11%);

	--kit-color-accent: hsl(220 90% 56%);
	--kit-color-on-accent: hsl(0 0% 100%);
	--kit-color-success: hsl(145 50% 38%);
	--kit-color-on-success: hsl(0 0% 100%);
	--kit-color-warning: hsl(35 80% 45%);
	--kit-color-on-warning: hsl(222 20% 10%);
	--kit-color-error: hsl(5 65% 48%);
	--kit-color-on-error: hsl(0 0% 100%);
	--kit-color-info: hsl(205 60% 42%);
	--kit-color-on-info: hsl(0 0% 100%);
	--kit-color-focus: hsl(35 90% 56%);
}

Media color scheme support

If you’d rather follow the operating system preference, override the tokens inside a prefers-color-scheme media query instead. No state to manage, no toggle to build:

@media (prefers-color-scheme: light) {
	:global([data-kit-theme='system']) {
		color-scheme: light;

		/* color-light */
	}
}

@media (prefers-color-scheme: dark) {
	:global([data-kit-theme='system']) {
		color-scheme: dark;

		/* color-dark */
	}
}

The trade-off is that users can’t switch themes from within your app the choice belongs to the system.

Our recommendation is to follow whatever your project already does. If you’re starting fresh, both approaches are valid: pick the attribute-based one if you plan to offer a theme switcher, and the media query if you just want to respect the user’s system setting.

CSS utilities

On top of colors, Lapikit ships two shared visual scales: elevation for depth and shape for corner radius. Every component uses them, so changing a token once updates your whole interface.

Elevation

Elevation tells users which surfaces sit above others: a card above the page, a menu above the card, a dialog above everything. Lapikit gives you six shadow levels, from 0 (flat) to 5 (floating).

0
data-elevation='0'
1
data-elevation='1'
2
data-elevation='2'
3
data-elevation='3'
4
data-elevation='4'
5
data-elevation='5'

Set the level with the elevation prop on any component that supports it, such as cards, buttons, chips, alerts, app bars, dropdowns and dialogs:

<kit:card elevation="2">Product details</kit:card>

The elevation can change with the interaction state. Pass an object with base, hover and active keys to lift a surface on hover and press it down on click:

<kit:card elevation={{ base: '1', hover: '3', active: '0' }}>Hover me</kit:card>
"classic"
`2`
"with hover"
`base: '1', hover: '3'`
"with active"
`base: '1', active: '4' `
"all"
`base: '1', hover: '5', active: '2' `

Under the hood, the prop sets data-elevation, data-elevation-hover and data-elevation-active attributes. The matching styles are global and loaded by <kit:app>, so you can also put these attributes on your own HTML elements:

<aside data-elevation="1">Custom panel</aside>

Each level combines two box-shadow layers: a short, sharp shadow and a wider, softer ambient one. Both are built from the same three tokens, so you can restyle every shadow in your app from one place:

VariableDefaultRole
--kit-color-shadowthemeBase color of every shadow
--kit-shadow-opacity30%Strength of the short, sharp shadow layer
--kit-shadow-ambient-opacity15%Strength of the wide, soft ambient layer

For example, raise both opacities in a dark theme, where shadows are harder to see on dark surfaces.

Shape

Shape controls the corner radius of components. The scale goes from square corners to fully rounded pills, and each step is a --kit-shape-* CSS variable.

none
--kit-shape-none
xs
--kit-shape-xs
sm
--kit-shape-sm
md
--kit-shape-md
lg
--kit-shape-lg
xl
--kit-shape-xl
full
--kit-shape-full

Pick a step with the rounded prop:

<kit:btn rounded="sm">Save</kit:btn>
<kit:card rounded="xl">Large rounded card</kit:card>

Use the same tokens in your own styles so your custom elements match the components:

.promo-banner {
	border-radius: var(--kit-shape-lg);
}

To change the overall look of your app, override the scale in :root. Lower values give a sharp, technical interface and higher values a softer, friendlier one, without touching any component. The full list of values is in the shape reference below.

Component styling

Each Lapikit component exposes its own scope variables.

Buttons, dialog boxes, cards, input fields, and other components can be customized independently, without modifying the rest of the design system.

In many libraries, global customization of a single component often requires:

  • Redefining internal selectors
  • Increasing CSS specificity
  • Or duplicating component styles

This complicates maintenance over time.

Per-component CSS variables

Each Lapikit component uses variables prefixed with the component name (e.g. --kit-btn-* for buttons).

Example:

layout.css
.kit-btn {
	--kit-btn-bg: hsl(262 80% 50%);
	--kit-btn-color: #ffffff;
	--kit-btn-radius: 999px;
}

This will apply to every instance of <kit:btn> across your app.

This approach allows you to customize a specific component without affecting the rest of the design system. To redefine them globally, limit the scope of the variables to the component’s root class.

For per-instance customization, use the s-style prop directly on the component instance:

btn
<kit:btn s-style={{ '--kit-btn-bg': 'orange' }}>Hello !</kit:btn>

CSS variable reference

Colors (surfaces)

VariableRole
--kit-color-surfaceBase page background
--kit-color-surface-1First elevation level (cards, panels)
--kit-color-surface-2Second elevation level (nested panels, hovered rows)
--kit-color-surface-3Highest elevation level (menus, popovers, modals)

Colors (text)

VariableRole
--kit-color-textPrimary text color
--kit-color-text-mutedSecondary text (labels, captions)
--kit-color-text-subtleLow-emphasis text (placeholders, hints)
--kit-color-text-disabledText on disabled elements

Colors (fills & lines)

VariableRole
--kit-color-fillNeutral interactive background (ghost buttons, inputs)
--kit-color-fill-hoverSame fill, hover state
--kit-color-fill-activeSame fill, pressed state
--kit-color-borderDefault border color
--kit-color-shadowBase color used to compose elevation shadows
--kit-color-transparentExplicit transparent value, for token-driven overrides

Colors (semantic)

Each role ships with an on- counterpart: the foreground color guaranteed to be readable on top of it.

VariableRole
--kit-color-accent / --kit-color-on-accentBrand color and its foreground
--kit-color-success / --kit-color-on-successPositive feedback
--kit-color-warning / --kit-color-on-warningCautionary feedback
--kit-color-error / --kit-color-on-errorDestructive actions and errors
--kit-color-info / --kit-color-on-infoNeutral informational feedback
--kit-color-focusFocus ring color

Shape

VariableValueRole
--kit-shape-none0Square corners
--kit-shape-xs0.25remChips, badges, small inputs
--kit-shape-sm0.375remButtons, inputs
--kit-shape-md0.625remCards, panels
--kit-shape-lg0.875remSheets, large containers
--kit-shape-xl1.125remModals, dialogs
--kit-shape-full9999pxPills and circular elements

Typography

VariableValueRole
--kit-fontsystem stackBase font stack
--kit-font-xs13pxCaptions, helper text
--kit-font-sm14pxDense UI, secondary labels
--kit-font-md15pxDefault body size
--kit-font-lg16pxEmphasized body text
--kit-font-xl17pxHeadings, titles

Spacing & density

space sets the base spacing unit; density is an additive offset applied on top of a component’s computed size.

VariableValueRole
--kit-space-compact2pxBase unit, compact scale
--kit-space-default4pxBase unit, default scale
--kit-space-comfortable6pxBase unit, comfortable scale
--kit-density-compact-4pxShrinks component size
--kit-density-default0pxLeaves component size untouched
--kit-density-comfortable4pxExpands component size

Elevation & states

VariableValueRole
--kit-shadow-opacity30%Opacity of the direct shadow layer
--kit-shadow-ambient-opacity15%Opacity of the ambient shadow layer
--kit-disabled-opacity0.55Opacity applied to disabled elements

Many component libraries lock styles behind complex configuration systems, preprocessors, or hard-coded themes.

This often results in:

  • Inconsistent overrides
  • Duplicate styles
  • Difficult theme maintenance
  • Global CSS conflicts
  • Unnecessary complexity in the build

Customizing a design system can quickly prove to be more difficult than creating one from scratch.

  • Lapikit maintains a style that closely resembles native CSS behavior.
  • Each component and theme setting can be modified directly using CSS variables.

Themes rely entirely on CSS variables:

  • Transitions between themes remain lightweight
  • Components automatically inherit updates
  • Most visual changes do not require components to be re-rendered

This simplifies theme management, even in large Svelte and SvelteKit projects.