Buy me a coffee

Styling from scratch

Keep the behavior and accessibility, throw away our look, and write your own CSS.

If your design is very different from ours, changing tokens one by one is slower than starting over. Every component is built so you can delete its <style> block and write a new one. The markup, keyboard support and screen reader support all stay the same.

What you can style

Every element has a class named after its part (.button, .trigger, .content, .item), and variants and sizes are data attributes:

button.svelte (markup, unchanged)
<button {...restProps} class={['button', className]} data-variant={variant} data-size={size}>
	{@render children?.()}
</button>

Open, active and highlighted states are attributes too, set by the component as you use it:

StateSelector
Open (dialog, popover, menu, select)[data-open]
Active tab[data-active]
Highlighted option or menu item[data-highlighted]
Orientation[data-orientation="horizontal"] / "vertical"
Disabled items and tabs[data-disabled]
Select showing its placeholder[data-placeholder]
Invalid form control[aria-invalid="true"]
Checkbox, radio and switch:checked, :indeterminate, :disabled

An example

Delete everything inside button.svelte's <style> block and write your own. Because the classes are in the same file, Svelte scopes them for you:

button.svelte (your new style block)
.button {
	padding: 0.5rem 1.25rem;
	border: 2px solid black;
	border-radius: 0;
	background: yellow;
	font-weight: 700;
	box-shadow: 4px 4px 0 black;

	&:hover {
		translate: -2px -2px;
		box-shadow: 6px 6px 0 black;
	}

	&:focus-visible {
		outline: 3px solid blue;
		outline-offset: 2px;
	}
}

.button[data-variant='outline'] {
	background: white;
}

.button[data-size='sm'] {
	padding: 0.25rem 0.75rem;
}

Every place you use <Button>, including inside Dialog and the other components that use it, now looks like this.

Things to keep

  • A visible focus style on everything you can click or type in, using :focus-visible. Keyboard users need it to see where they are.
  • Hidden states. Dialogs, popovers and menus are hidden until [data-open] is set. Keep the rules that show and hide them, or copy them from the original file.
  • Enough contrast between text and background (4.5 to 1 for normal text).

You can keep using the tokens in your new styles, or none of them. Once no component reads them, you can remove the tokens.css import too.