# Tailwind CSS

> Using @svelte-lean/styles with Tailwind CSS v4: the layer order, the import order, @theme inline mappings from the --slean-* tokens and overriding a primitive with utilities.

Page: https://svelte-lean.vercel.app/styling/tailwind · Markdown: https://svelte-lean.vercel.app/styling/tailwind.md · Index: https://svelte-lean.vercel.app/llms.txt

@svelte-lean/styles and Tailwind CSS v4 share one cascade through a single layer statement; the package does not depend on Tailwind.

## Setup

`src/app.css`

```css
/* src/app.css. The layer statement comes first: Tailwind's theme and preflight (base) sit
 * below Svelte Lean, Tailwind's components and utilities above it. The package files declare
 * their rules in slean.* sublayers, so they are imported without layer(). */
@layer theme, base, slean, components, utilities;

@import 'tailwindcss';

@import '@svelte-lean/styles/tokens.css';
@import '@svelte-lean/styles/base.css';
@import '@svelte-lean/styles/button.css';
@import '@svelte-lean/styles/input.css';
@import '@svelte-lean/styles/menu.css';

/* Tailwind's dark: variant follows the same class the tokens read. */
@custom-variant dark (&:where(.dark, .dark *));
```

- Every package file declares its rules in `slean.*` sublayers; the statement places `slean` between preflight (`base`) and Tailwind's `components`.
- The statement comes before `@import 'tailwindcss'`. Without it, `slean` lands after `utilities` and beats every utility.
- Import the package files without `layer()`, or they nest one level deeper, unordered.
- Import only the files the page uses; `menu.css` brings `popover.css` itself.

## Preflight

Preflight applies first; package rules replace it on every element with `data-slean` or `data-slean-part`. Content inside a primitive that is not a part (a dialog body, a tab panel) keeps preflight.

## Tokens as Tailwind colors

`@theme inline` exposes the tokens as `bg-primary`, `border-input`, `text-muted-foreground`; `inline` keeps the `var()`, so utilities follow the dark palette and theme scopes.

`src/app.css`

```css
/* Tailwind colors and radii that read the Svelte Lean tokens. inline keeps the var() in the
 * generated utilities, so a theme scope or the dark palette changes them at run time. */
@theme inline {
	--color-background: var(--slean-bg);
	--color-foreground: var(--slean-fg);
	--color-surface: var(--slean-surface);
	--color-muted: var(--slean-muted);
	--color-muted-foreground: var(--slean-fg-muted);
	--color-border: var(--slean-border);
	--color-input: var(--slean-control-border);
	--color-ring: var(--slean-focus-ring-color);
	--color-primary: var(--slean-primary-main);
	--color-primary-foreground: var(--slean-primary-contrast-text);
	--color-destructive: var(--slean-error-main);
	--radius-sm: var(--slean-radius-sm);
	--radius-md: var(--slean-radius-md);
	--radius-lg: var(--slean-radius-lg);
}
```

The reverse direction points the package tokens at Tailwind's theme:

`src/app.css`

```css
/* The other direction: point the Svelte Lean tokens at Tailwind's theme variables, so the
 * primitives take the palette of an existing Tailwind design. Unlayered, like any override. */
:root {
	--slean-primary-main: var(--color-indigo-600);
	--slean-primary-dark: var(--color-indigo-700);
	--slean-primary-soft: var(--color-indigo-50);
	--slean-primary-soft-text: var(--color-indigo-700);
	--slean-font-sans: var(--font-sans);
}
```

## Dark mode

The tokens switch on `prefers-color-scheme`, `data-theme="dark"` and the `dark` class ([Themes](https://svelte-lean.vercel.app/styling/themes.md#dark-theme)); the `@custom-variant` line gives `dark:` the same class.

## Overriding a primitive with utilities

`utilities` comes after `slean`, so a utility wins. A utility without a state variant replaces the property in every state; pair it, as `hover:bg-emerald-700` does.

`Page.svelte`

```svelte
<!-- The utilities layer comes after slean, so a utility wins over the package rule it
     meets, whatever the selector. A state the package styles needs its own variant: a plain
     bg-* also replaces the hover background. -->
<button
	type="button"
	data-slean="button"
	class="rounded-full bg-emerald-600 px-8 shadow-lg hover:bg-emerald-700"
>
	Publish
</button>

<input type="text" data-slean="input" class="w-64 rounded-none border-2 border-primary" />

<!-- Tailwind's own markup can use the token colors from @theme inline. -->
<p class="rounded-md border border-border bg-muted px-2 py-1 text-muted-foreground">…</p>
```

> **Note** A utility changes one element. To change every button, override a token or write an unlayered rule on the protocol attribute.
