# Styling (/docs/styling)



Luke UI ships static CSS. It does not inject styles at runtime. Import the shared stylesheet and a
theme stylesheet once. Then use component props for the variations each component supports.

## Choose a styling approach [#choose-a-styling-approach]

Work from the most specific public API to the broadest one.

1. Use a component's props for its supported appearance, size, state, and behaviour.
2. Use layout utilities for spacing, sizing, and responsive structure around components.
3. Use semantic variables for application-owned custom UI when no component fits.
4. Author a custom theme when the product needs a different visual foundation everywhere.

Read [Composition](/docs/composition) when the choice is between a component and a documented
primitive rather than between styling mechanisms.

| Guidance | Practices                                                                                  |
| -------- | ------------------------------------------------------------------------------------------ |
| Do       | Use a supported component prop for its appearance, size, state, or behaviour.              |
| Do       | Use a layout utility for its element contract, and `vars` for application-owned custom UI. |
| Don't    | Target generated selectors or implementation-state attributes such as `data-pressed`.      |

Do not override component recipe selectors or implementation-state attributes such as
`data-hovered`, `data-pressed`, or `data-focus-visible`. They are not supported styling hooks and
can change without a migration path.

### Start with component props [#start-with-component-props]

Components are intentionally opinionated. Their public props cover supported variants, states, and
behaviour. The active identity supplies semantic colours, font roles, radii, and depth. Luke UI
defines its type and spacing scale in source.

apps/docs/src/samples/styling/component-props.tsx

```tsx
import { Button } from '@luke-ui/react/button';

export function SaveButton() {
	return (
		<Button appearance="subtle" size="small" tone="accent">
			Save changes
		</Button>
	);
}
```

### Apply a component recipe [#apply-a-component-recipe]

Import a recipe when you own the element and need that component's visual treatment. Use the
component when you want its behaviour as well.

Each recipe lives on the component or primitive entrypoint that owns it. Import `buttonRecipe` from
`@luke-ui/react/button`. There is no `@luke-ui/react/recipes` barrel.

Recipes follow a fixed name. The function is the component in camel case plus `Recipe`. The variants
type is the component in Pascal case plus `RecipeVariants`.

apps/docs/src/examples/styling/button-recipe.tsx

```tsx
import { buttonRecipe } from '@luke-ui/react/button';

export default () => {
	return (
		<a className={buttonRecipe({ appearance: 'subtle' })} href="#settings">
			Settings
		</a>
	);
};
```

A single-part recipe such as `buttonRecipe` returns the finished class string. Pass the same variant
names the component accepts, plus an optional `className` of your own. The recipe appends your class
after its own, so do not wrap the result in another composition helper.

```tsx
import { buttonRecipe, type ButtonRecipeVariants } from '@luke-ui/react/button';

const variants: ButtonRecipeVariants = { appearance: 'subtle', tone: 'neutral' };
const className = buttonRecipe({ ...variants, className: 'my-class' });
```

A slotted recipe such as `inputGroupRecipe` returns one function per part. Choose variants once at
the outer call, then call the part you are styling with an optional `{ className }`.

```tsx
import { inputGroupRecipe } from '@luke-ui/react/primitives/input-group';

const { group, control } = inputGroupRecipe({ size: 'medium' });
const groupClassName = group({ className: 'my-class' });
```

Do not import a recipe to restyle a Luke UI component from the outside. Use the component's props
for supported variation.

### Use layout utilities for structure [#use-layout-utilities-for-structure]

`Box` and layout utilities from `@luke-ui/react/styles` handle spacing, sizing, positioning, and
responsive structure around components. They do not set semantic colour, typography, or pseudo
states. Read [Layout](/docs/layout) for the full API.

### Use semantic variables for custom UI [#use-semantic-variables-for-custom-ui]

The public `vars` token contract lets an application-owned element follow the active theme.

apps/docs/src/samples/styling/semantic-variables.tsx

```tsx
import { vars } from '@luke-ui/react/theme';
import type { PropsWithChildren } from 'react';

export function FloatingPanel({ children }: PropsWithChildren) {
	return (
		<aside
			style={{
				backgroundColor: vars.color.surface.floating,
				borderRadius: vars.radius.surface,
				boxShadow: vars.depth.floating,
				color: vars.color.text.primary,
			}}
		>
			{children}
		</aside>
	);
}
```

The token contract is public. Component selectors, generated palette values, and theme
implementation details are not. See the [token reference](/docs/token-reference) for the full
contract.

### Change the visual foundation with a custom theme [#change-the-visual-foundation-with-a-custom-theme]

Use a [custom theme](/docs/authoring-a-theme) when a product needs a different identity, typeface,
or semantic colour system. `defineTheme` produces a static stylesheet for the full semantic contract
from a curated accent and neutral character. It is not a per-component override tool.

## Set up static styles [#set-up-static-styles]

Import the shared stylesheet and one theme stylesheet, then apply `rootClassName`. Luke UI scopes
the reset to that root.

apps/docs/src/samples/styling/static-styles.tsx

```tsx
import '@luke-ui/react/stylesheet.css';
import '@luke-ui/react/themes/tactile/stylesheet.css';
import { rootClassName } from '@luke-ui/react/theme';
import type { PropsWithChildren } from 'react';

export function App({ children }: PropsWithChildren) {
	return <div className={rootClassName}>{children}</div>;
}
```

Read [Installation](/docs/installation) for the first-run path. Read
[Applying a theme](/docs/applying-a-theme) for colour modes, portals, and more than one theme.

## Use application CSS alongside Luke UI [#use-application-css-alongside-luke-ui]

Luke UI's stylesheet uses six cascade layers, from lowest to highest priority: `reset`, `theme`,
`base`, `recipes`, `structural`, and `utilities`. That order does not change with stylesheet import
order. The reset applies only under `rootClassName`.

The `base` layer is reserved for application defaults such as Tailwind Preflight. Luke UI declares
it empty so it stays below `recipes`. Put component styles in `recipes`, retained global selectors
such as skeleton masks in `structural`, and one-off overrides in `utilities`.

If your application also uses cascade layers, declare its layer order before you import stylesheets.

```css
@layer reset, theme, base, recipes, structural, utilities;

@import '@luke-ui/react/stylesheet.css';
@import 'tailwindcss';
```

Tailwind utilities, CSS Modules, and application CSS work well for application-owned layout and
custom elements. Put Tailwind classes on surrounding elements or `Box`. Use CSS Modules or
application styles with public semantic variables for custom UI. Unlayered application CSS sits
outside Luke UI's layers, so do not use it to reach into a component's internal DOM.

```tsx
import { Box } from '@luke-ui/react/box';

<Box className="mx-auto" maxInlineSize="64rem" paddingInline="sp16">
	{children}
</Box>;
```

When a CSS Module or application stylesheet needs a token, use the stable `--luke-*` variable listed
in the [token reference](/docs/token-reference). Do not couple application CSS to undocumented
selectors or implementation attributes.

## Continue learning [#continue-learning]

<Cards>
  <Card href="/docs/layout" title="Layout">
    Use Box and Sprinkles for responsive structure.
  </Card>

  <Card href="/docs/color" title="Colour">
    Choose semantic surfaces and roles for custom UI.
  </Card>

  <Card href="/docs/token-reference" title="Token reference">
    Browse every public semantic CSS variable.
  </Card>

  <Card href="/docs/authoring-a-theme" title="Author a theme">
    Create a product-owned visual foundation when the bundled identities do not fit.
  </Card>
</Cards>
