22
33All classes use the ` l-ui- ` prefix with BEM naming. Use these in host app views. Do not use raw Tailwind utilities for engine-provided patterns as they will not be generated by the host app's Tailwind build.
44
5+ ## Naming conventions
6+
7+ Two patterns deviate from strict BEM by design - leave them in place rather than "fixing" them into elements:
8+
9+ ** ` *-container ` shells.** Several blocks have a sibling ` *-container ` class (` l-ui-header-container ` , ` l-ui-navigation-container ` , ` l-ui-panel-container ` , ` l-ui-table-container ` , ` l-ui-pagy-container ` , ` l-ui-checkbox-container ` , ` l-ui-select-container ` ). These are positioning shells responsible for fixed/overlay placement, scroll boundaries, and click-outside scopes. They are treated as their own blocks rather than ` __container ` elements because they have distinct responsibilities from the inner block, are sometimes used independently in tests/docs, and several BEM dialects accept this. Use the ` *-container ` suffix consistently for any new shell of this kind.
10+
11+ ** Bare-link styling.** ` .l-ui-page ` and ` .l-ui-panel__body ` style descendant ` <a> ` elements that do not already carry an ` l-ui- ` class:
12+
13+ ``` css
14+ .l-ui-page a :not ([class *= " l-ui-" ]),
15+ .l-ui-panel__body a :not ([class *= " l-ui-" ]) { ... }
16+ ```
17+
18+ This gives author-written links inside long-form content (Markdown, prose, ad-hoc views) consistent underline/colour treatment without forcing an explicit class on every link. Engine elements opt out automatically because their class names contain ` l-ui- ` . Side effect: any host-app class containing the substring ` l-ui- ` will also opt an ` <a> ` out of bare-link styling.
19+
520## Page layout
621
722```
823.l-ui-page Main content wrapper with responsive padding
924.l-ui-page--with-navigation Left margin for sidebar on desktop
10- .l-ui-page--vertically- centered Centred layout (e.g. login pages)
11- .l-ui-page--width- constrained Max-width container
25+ .l-ui-page__vertically- centered Centred layout element (e.g. login pages)
26+ .l-ui-page__width- constrained Max-width container element
1227```
1328
1429## Buttons
1530
16- Standalone variants (use one of these, not combined with each other ):
31+ Always combine the ` l-ui-button ` base class with a colour modifier (e.g. ` l-ui-button l-ui-button--primary ` ):
1732
1833```
19- .l-ui-button Plain button with padding and focus ring
20- .l-ui-button--primary Accent-coloured solid button
21- .l-ui-button--danger Solid red button (for destructive actions)
22- .l-ui-button--outline Bordered button
23- .l-ui-button--outline-danger Red bordered button (for destructive actions)
24- .l-ui-button--icon Icon-only button (fixed size, no text)
25- .l-ui-button--navigation-toggle Mobile navigation toggle
26- .l-ui-button--panel-close Panel close button
34+ .l-ui-button Base class (required with the modifiers below)
35+ .l-ui-button--primary Accent-coloured solid button
36+ .l-ui-button--danger Solid red button (for destructive actions)
37+ .l-ui-button--outline Bordered button
38+ .l-ui-button--outline-danger Red bordered button (for destructive actions)
39+ .l-ui-button--full Full-width (e.g. l-ui-button l-ui-button--primary l-ui-button--full)
40+ .l-ui-button--small Compact 32px-tall variant
2741```
2842
29- Modifiers (combine with a standalone variant above ):
43+ Icon variants (combine with the ` l-ui-button ` base ):
3044
3145```
32- .l-ui-button--full Full-width (e.g. l-ui-button--primary l-ui- button--full )
33- .l-ui-button--small Compact 32px-tall variant (e.g. l-ui-button--primary l-ui-button--small)
46+ .l-ui-button--icon Icon-only button (fixed size, no text )
47+ .l-ui-button--navigation-toggle Mobile navigation toggle
3448```
3549
3650Any button variant is automatically styled as disabled when the ` disabled ` HTML attribute is present - no extra class needed.
@@ -39,12 +53,14 @@ For destructive actions use `l-ui-button--danger` (solid) or `l-ui-button--outli
3953
4054## Surfaces
4155
56+ Always combine the ` l-ui-surface ` base class with any modifiers (e.g. ` l-ui-surface l-ui-surface--highlighted ` ):
57+
4258```
43- .l-ui-surface Rounded, padded container
59+ .l-ui-surface Base class (required with the modifiers below)
4460.l-ui-surface--highlighted Darker background variant
4561.l-ui-surface--sm Smaller padding
4662.l-ui-surface--collapsible Wraps a <details> element
47- .l-ui-surface--collapsible-highlighted Highlighted variant
63+ .l-ui-surface--collapsible-highlighted Highlighted collapsible variant
4864.l-ui-surface__summary Collapsible toggle (on <summary>)
4965.l-ui-surface__chevron Chevron indicator (rotates on open)
5066.l-ui-surface__content Collapsible content area
@@ -55,7 +71,7 @@ For destructive actions use `l-ui-button--danger` (solid) or `l-ui-button--outli
5571```
5672.l-ui-form Form container
5773.l-ui-form__group Vertical field group with spacing
58- .l-ui-form__group--large-gap Larger spacing variant
74+ .l-ui-form__group--large-gap Larger spacing modifier (combine with l-ui-form__group)
5975.l-ui-form__field Input/textarea styling
6076.l-ui-form__errors Error summary box
6177.l-ui-form__errors-list Bulleted error list
@@ -65,14 +81,16 @@ For destructive actions use `l-ui-button--danger` (solid) or `l-ui-button--outli
6581.l-ui-form__required Required indicator (*)
6682
6783.l-ui-label Form label
68- .l-ui-label--checkbox Checkbox label variant
84+
85+ .l-ui-checkbox-container Checkbox row (input + label)
86+ .l-ui-checkbox Checkbox input
87+ .l-ui-checkbox-container__label Checkbox label element
6988
7089.l-ui-select Select dropdown
71- .l-ui-select-wrapper Select wrapper (custom arrow)
90+ .l-ui-select-container Select wrapper (custom arrow)
7291
7392.l-ui-search-inline Inline search form layout
7493
75- .l-ui-checkbox-container Checkbox container
7694.l-ui-radio Radio button group
7795.l-ui-radio__item Radio item wrapper
7896.l-ui-radio__input Radio input element
@@ -90,13 +108,15 @@ For destructive actions use `l-ui-button--danger` (solid) or `l-ui-button--outli
90108.l-ui-table__header <thead> row
91109.l-ui-table__header-cell <th> cell
92110.l-ui-table__header-cell--action Right-aligned action header
111+ .l-ui-table__header-cell--sortable Marker class for sortable headers (no engine styles; host-app/JS hook)
93112.l-ui-table__sort-link Sortable header link
94113.l-ui-table__sort-indicator Sort direction indicator (arrow)
95114.l-ui-table__body <tbody>
96115.l-ui-table__cell Regular <td> cell
97116.l-ui-table__cell--primary Bold cell (typically first column, use <th scope="row">)
98117.l-ui-table__cell--action Right-aligned action cell
99- .l-ui-table__action--danger Danger action link
118+ .l-ui-table__action Action link/button (inside a __cell--action)
119+ .l-ui-table__action--danger Danger modifier (combine with l-ui-table__action)
100120.l-ui-table-container Overflow wrapper for responsive tables
101121```
102122
@@ -110,14 +130,14 @@ WCAG 2.2 AA table pattern:
110130 <tr >
111131 <th scope =" col" class =" l-ui-table__header-cell" >Name</th >
112132 <th scope =" col" class =" l-ui-table__header-cell" >Email</th >
113- <th scope =" col" class =" l-ui-table__header-cell--action" >Actions</th >
133+ <th scope =" col" class =" l-ui-table__header-cell l-ui-table__header-cell --action" >Actions</th >
114134 </tr >
115135 </thead >
116136 <tbody class =" l-ui-table__body" >
117137 <tr >
118- <th scope =" row" class =" l-ui-table__cell--primary" >Alice</th >
138+ <th scope =" row" class =" l-ui-table__cell l-ui-table__cell --primary" >Alice</th >
119139 <td class =" l-ui-table__cell" >alice@example.com</td >
120- <td class =" l-ui-table__cell--action" >
140+ <td class =" l-ui-table__cell l-ui-table__cell --action" >
121141 <a href =" /users/1/edit" >Edit</a >
122142 </td >
123143 </tr >
@@ -140,20 +160,23 @@ Always combine the base block with one variant modifier (e.g. `class="l-ui-notic
140160## Badges
141161
142162```
143- .l-ui-badge Base badge
163+ .l-ui-badge Base badge (required alongside a colour modifier)
144164.l-ui-badge--rounded Pill shape
145165.l-ui-badge--default Grey
146166.l-ui-badge--success Green
147167.l-ui-badge--warning Yellow
148168.l-ui-badge--danger Red
149169```
150170
171+ Always combine the base block with a modifier, e.g. ` <span class="l-ui-badge l-ui-badge--success"> ` .
172+
151173## Tabs
152174
153175```
176+ .l-ui-tabs Tabs wrapper (data-controller="l-ui--tabs")
154177.l-ui-tabs__list Tab list container (role="tablist")
155- .l-ui-tabs__tab Tab button
156- .l-ui-tabs__tab--active Active tab with accent border
178+ .l-ui-tabs__tab Tab button (base class, required)
179+ .l-ui-tabs__tab--active Active tab with accent border (combine with l-ui-tabs__tab)
157180.l-ui-tabs__panel Tab panel content
158181```
159182
@@ -196,22 +219,22 @@ Always combine the base block with one variant modifier (e.g. `class="l-ui-notic
196219## Navigation
197220
198221```
199- .l-ui-navigation-container Sidebar container
200- .l-ui-navigation-container. open Visible sidebar
201- .l-ui-backdrop Base backdrop (always pair with a variant)
202- .l-ui-backdrop--navigation Navigation overlay (use with .l-ui-backdrop)
203- .l-ui-backdrop. open Visible backdrop
222+ .l-ui-navigation-container Sidebar container
223+ .l-ui-navigation-container-- open Visible sidebar (toggled by Stimulus)
224+ .l-ui-backdrop Base backdrop (always pair with a variant)
225+ .l-ui-backdrop--navigation Navigation overlay (use with .l-ui-backdrop)
226+ .l-ui-backdrop-- open Visible backdrop (toggled by Stimulus)
204227.l-ui-navigation Nav flexbox
205228.l-ui-navigation__links Nav links list
206- .l-ui-navigation__item Nav item
207- .l-ui-navigation__item--active Active nav item (highlighted bg )
229+ .l-ui-navigation__item Nav item (base class, required)
230+ .l-ui-navigation__item--active Active nav item (combine with l-ui-navigation__item )
208231.l-ui-navigation__item-icon Icon image inside a nav item
209232.l-ui-navigation__item-icon-slot Wrapper for caller-supplied icon HTML (e.g. icon fonts)
210233.l-ui-navigation__item-label Label span inside a nav item
211234.l-ui-navigation__section Section group (li)
212235.l-ui-navigation__section--has-heading Section that has a visible heading
213236.l-ui-navigation__section--separated Section with top border separator
214- .l-ui-navigation__section--collapsible Section with toggle button heading
237+ .l-ui-navigation__section--collapsible Marker class for collapsible sections (no engine styles; host-app/JS hook)
215238.l-ui-navigation__section-heading Plain section label (small, uppercase, muted)
216239.l-ui-navigation__section-toggle Collapsible section heading (item-row sized button)
217240.l-ui-navigation__section-chevron Toggle chevron (rotates when closed)
@@ -242,11 +265,13 @@ Always combine the base block with one variant modifier (e.g. `class="l-ui-notic
242265
243266```
244267.l-ui-panel-container Side panel container
245- .l-ui-panel-container. open Visible panel
268+ .l-ui-panel-container-- open Visible panel (toggled by Stimulus)
246269.l-ui-panel Panel flexbox
247270.l-ui-panel__button Floating action button
248271.l-ui-panel__button--dragging During drag
249272.l-ui-panel__button--snapping Snapping to edge
273+ .l-ui-panel__button--hidden Hidden when panel is open (toggled by Stimulus)
274+ .l-ui-panel__close-button Panel close button (combine with l-ui-button l-ui-button--icon)
250275.l-ui-panel__icon Panel button inline SVG icon
251276.l-ui-panel__icon--light Panel button icon (light, for custom image override)
252277.l-ui-panel__icon--dark Panel button icon (dark, for custom image override)
@@ -266,8 +291,8 @@ Always combine the base block with one variant modifier (e.g. `class="l-ui-notic
266291.l-ui-conversation__composer-input Textarea
267292.l-ui-conversation__separator Date separator
268293
269- .l-ui-message Message wrapper
270- .l-ui-message--sent Sent message (right-aligned)
294+ .l-ui-message Message wrapper (required with --sent)
295+ .l-ui-message--sent Sent message modifier (right-aligned; combine with l-ui-message )
271296.l-ui-message__avatar User avatar
272297.l-ui-message__bubble Message bubble
273298.l-ui-message__author Author name
@@ -276,7 +301,7 @@ Always combine the base block with one variant modifier (e.g. `class="l-ui-notic
276301.l-ui-message__timestamp Timestamp
277302
278303.l-ui-stream-fade Fade-in for streamed chunks as they arrive (0.5s ease-out)
279- .l-ui-stream-fade-word Per-word staggered fade-in for completed responses
304+ .l-ui-stream-fade__word Per-word staggered fade-in for completed responses
280305 (0.5s ease-out; set --i to the word index for a 25ms
281306 stagger, capped at 1s)
282307```
0 commit comments