Getting started
This page declares a few design tokens, styles a template with css() and
shows what the bundle writes. It assumes the bundle is installed and the
stylesheet is loaded, as shown in Installation.
Declare tokens
Tokens are the values your styles are allowed to use: colors, spacing, radii and so on. Declare them in the bundle configuration:
1 2 3 4 5 6 7 8 9 10 11 12
# config/packages/ux_css.yaml
ux_css:
tokens:
colors:
blue: { 500: '#3b82f6', 600: '#2563eb' }
gray: { 50: '#f9fafb', 900: '#111827' }
spacing: { sm: '0.5rem', md: '1rem', lg: '2rem' }
radii: { md: '0.375rem' }
semantic_tokens:
colors:
primary: '{colors.blue.500}'
fg: { base: '{colors.gray.900}', _dark: '{colors.gray.50}' }
tokens holds raw values, in groups such as blue.500.
semantic_tokens gives them names that describe their role: primary
points to blue.500, and fg changes value in dark mode. See
Design tokens for the details.
Style a template
Call css() inside a class attribute, with a hash of properties:
1 2 3 4 5 6 7 8
{# templates/product/show.html.twig #}
{% extends 'base.html.twig' %}
{% block body %}
<article class="{{ css({ p: 'md', rounded: 'md', bg: 'gray.50', color: 'fg' }) }}">
<h1 class="{{ css({ color: 'primary' }) }}">{{ product.name }}</h1>
</article>
{% endblock %}
p is short for padding, and rounded for borderRadius. Each
value is the name of a token. The page renders these classes:
1 2 3
<article class="p_md bdr_md bg_gray.50 c_fg">
<h1 class="c_primary">...</h1>
</article>
The classes are resolved when Twig compiles the template. Rendering the page only prints them.
What the bundle writes
In dev, the bundle updates var/ux_css/styles.css before responding to every
request that follows a template change. After the first page load, the file
contains every token as a CSS variable, then one rule per class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
@layer tokens, utilities;
@layer tokens {
:where(:root, :host) {
--colors-blue-500: #3b82f6;
--colors-gray-50: #f9fafb;
--spacing-md: 1rem;
/* ... */
--colors-primary: var(--colors-blue-500);
--colors-fg: var(--colors-gray-900);
}
.dark {
--colors-fg: var(--colors-gray-50);
}
}
@layer utilities {
.p_md { padding: var(--spacing-md); }
.bdr_md { border-radius: var(--radii-md); }
.bg_gray\.50 { background: var(--colors-gray-50); }
.c_fg { color: var(--colors-fg); }
.c_primary { color: var(--colors-primary); }
}
The bundle reads every template of the application, not only the ones you open. So a template rendered later, for example by a Live Component, finds its rules in the file. There is no watcher to start.
Add a hover and a breakpoint
Conditions start with an underscore, and breakpoints are written as is:
1 2 3 4 5
<a href="{{ path('product_index') }}" class="{{ css({
color: 'primary',
_hover: { color: 'blue.600' },
p: { base: 'sm', md: 'md' }
}) }}">Back to the list</a>
This gives c_primary hover:c_blue.600 p_sm md:p_md: the link turns darker
on hover, and its padding grows from sm to md on screens at least
48rem wide. Conditions and breakpoints lists every condition and breakpoint.
Switch to dark mode
The fg token has a value for the _dark condition. By default, that
condition applies inside an element that has the dark class:
1 2
{# templates/base.html.twig #}
<html lang="en" class="dark">
Every color: 'fg' now uses gray.50, with no change to the templates.
Conditions and breakpoints shows how to use another selector, or the operating system
preference.
Make a mistake
Misspell a token, and the page shows a Twig error that points to the line:
1
<h1 class="{{ css({ color: 'primry' }) }}">{{ product.name }}</h1>
1 2
Unknown colors token "primry". Did you mean "primary" in
"product/show.html.twig" at line 6?
The same check runs in lint:twig, and cache:warmup fails on it in the
prod environment, so CI catches the mistake too. Catching mistakes lists
what is checked.
Next steps
- Design tokens covers how to declare tokens and how to use them in hand-written CSS.
- Token categories lists every token category.
- The css() function is the reference for the
css()syntax. - Dynamic styles explains values only known at runtime.