@troennes/minium 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/integrations/prism.css +4 -2
- package/dist/minium.css +201 -88
- package/dist/minium.min.css +1 -1
- package/llms.txt +1072 -0
- package/package.json +4 -3
package/llms.txt
ADDED
|
@@ -0,0 +1,1072 @@
|
|
|
1
|
+
# Minium CSS
|
|
2
|
+
Minium: the minimum CSS and HTML to build anything.
|
|
3
|
+
|
|
4
|
+
Minium is a semantic-first CSS library that makes ordinary HTML look good, then adds class-light layouts and components for building real interfaces.
|
|
5
|
+
|
|
6
|
+
## Minium CSS install notes
|
|
7
|
+
1. Install the package with `npm install @troennes/minium`.
|
|
8
|
+
2. In a bundled application, import the core stylesheet with `import "@troennes/minium";` or the minified build with `import "@troennes/minium/min";`. The npm package includes PT Sans and Inconsolata under `dist/fonts/`; bundlers that process CSS `url()` assets include them automatically.
|
|
9
|
+
3. If the tools cannot import CSS from a package, copy the complete `node_modules/@troennes/minium/dist/` directory into the project's public assets and link the copied stylesheet. Keep `fonts/` beside the stylesheet so its relative font URLs continue to work.
|
|
10
|
+
4. To use jsDelivr without installing the package, load `https://cdn.jsdelivr.net/npm/@troennes/minium@0.3.0/dist/minium.min.css`. The relative font URLs load the bundled fonts from the same pinned CDN package. Do not add separate font links. Keep the version pinned unless the project deliberately upgrades Minium.
|
|
11
|
+
5. To modify and build the source CSS, download `https://github.com/troennes/minium/archive/refs/heads/main.zip`, extract it, and open a terminal in the extracted `minium-main` directory. This download follows the moving `main` branch and requires Node.js 22 or later. Run `npm install`, then `npm run build`. Copy the complete generated `dist/` directory into the project's public assets and link `minium.min.css`. Keep the generated `fonts/` directory beside the stylesheet. The build also includes the readable `minium.css` and optional integration styles in `dist/integrations/`.
|
|
12
|
+
6. Do not assume Tailwind, Bootstrap, or JavaScript component plugins exist. Minium CSS is plain CSS.
|
|
13
|
+
7. Customize the system primarily through CSS custom properties, especially the semantic tokens in the theme layer.
|
|
14
|
+
8. The library is built around semantic HTML first, layouts second, components/modifiers third, utilities fourth, and project classes for anything else.
|
|
15
|
+
|
|
16
|
+
## How HTML feels with Minium
|
|
17
|
+
Minium minimizes both the CSS shipped by the library and the HTML written by the user. The library carries the cost so users write less. Reach for tools in this order:
|
|
18
|
+
|
|
19
|
+
1. **Semantic HTML, no classes.** `main`, `article`, `h1`, `p`, `ul`, `table`, `form`, `button`, `dialog`, `details` already look right. Top-level `header` and `footer` as direct children of `body` get automatic page-shell styling.
|
|
20
|
+
2. **One layout or component class.** `.cluster`, `.grid`, `.sidebar`, `.card`, `.alert` carry their own composition and visual defaults.
|
|
21
|
+
3. **A small modifier.** `.primary`, `.danger`, `.small`, `.secondary`, `.slim` — short words that tweak the layout/component.
|
|
22
|
+
4. **A token-bounded utility.** `gap-l`, `p-m`, `radius-s`, `fg-muted` adjust one variable at a time. Preferred over `style="--var: ..."`.
|
|
23
|
+
5. **A project class.** Anything specific to your project (`.hero`, `.pricing-comparison`, `.product-card`) lives in your own `@layer project` CSS.
|
|
24
|
+
|
|
25
|
+
## Architecture
|
|
26
|
+
Minium uses cascade layers to control specificity. The order is:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
@layer tokens, theme, reset, base, layout, components, project, utilities;
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- `tokens` — library defaults: the default theme's color roles, semantic colors, type scale, spacing scale, shadows, radii, fonts.
|
|
33
|
+
- `theme` — color theme files and your own token overrides. Overrides `tokens`.
|
|
34
|
+
- `reset` — foundational reset rules.
|
|
35
|
+
- `base` — element defaults (the "no-class HTML looks good" layer).
|
|
36
|
+
- `layout` — composition primitives. Structural only, no visual styling.
|
|
37
|
+
- `components` — curated blocks and objects (card, badge, alert, modal, dropdown, tabs, accordion, avatar, icon, tooltip, etc.).
|
|
38
|
+
- `project` — your own classes. Not shipped by the library.
|
|
39
|
+
- `utilities` — token-bounded shortcuts. Escape hatches, not building blocks.
|
|
40
|
+
|
|
41
|
+
## Minium CSS usage rules
|
|
42
|
+
1. Prefer semantic HTML before adding classes. Many patterns are intentionally styled through native elements alone.
|
|
43
|
+
2. Use documented layout classes for composition: `.flow`, `.cluster`, `.container`, `.grid`, `.repel`, `.switcher`, `.sidebar`, and `.frame`.
|
|
44
|
+
3. Use documented component classes only where they exist, such as `.card`, `.alert`, `.badge`, `.pill`, `.avatar`, `.icon`, `.dropdown`, and `.skeleton`.
|
|
45
|
+
4. Use semantic state and structure attributes where the library expects them: `role="group"`, `aria-current="page"`, `aria-invalid`, `aria-busy`, `aria-disabled`, and native attributes like `open`, `disabled`, `readonly`, `multiple`, and `popover`. Tooltips use `data-tooltip` and `data-placement` (see Tooltip).
|
|
46
|
+
5. Do not invent large component APIs. If a pattern is not described here, build it from semantic HTML plus layout primitives, and a small amount of project CSS.
|
|
47
|
+
6. Prefer theme-token overrides over component-specific overrides. Change shared variables first, then override a specific component only if necessary.
|
|
48
|
+
7. Prefer token-bounded utility classes (`gap-l`, `p-m`, `bg-raised`, `radius-s`) over inline `style="--var: ..."`.
|
|
49
|
+
8. Automatic vertical rhythm already exists in all components. Avoid stacking extra margin utilities or wrapping everything in `.flow` without reason.
|
|
50
|
+
9. When a link should behave visually like a button, use `role="button"` and button modifiers rather than styling a plain text link as a pseudo-button.
|
|
51
|
+
10. For forms, use the native HTML control pattern first. Minium CSS styles labels, helper text, validation state, and grouped controls around semantic form markup.
|
|
52
|
+
11. For navigation, breadcrumbs, pagination, dropdown menus, accordions, and modals, prefer the native HTML structures described below instead of custom JavaScript widgets.
|
|
53
|
+
|
|
54
|
+
## Customization model
|
|
55
|
+
1. Minium CSS is configured through custom properties.
|
|
56
|
+
2. The most important token groups are:
|
|
57
|
+
`--size-*` for type scale,
|
|
58
|
+
`--space-*` and `--gap` for spacing,
|
|
59
|
+
`--flow-space*` for vertical rhythm,
|
|
60
|
+
`--content-width` and `--main-width` for widths,
|
|
61
|
+
`--border-radius-*`, `--border-width`, and `--shadow-*` for shape and depth,
|
|
62
|
+
`--color-*` for semantic colors.
|
|
63
|
+
3. Most components consume semantic tokens instead of hard-coded values. If you change a token like `--color-primary`, buttons, links, alerts, badges, and focus styles update together.
|
|
64
|
+
4. Do not edit the library files. Override tokens in `@layer theme { :root { ... } }` in your own stylesheet.
|
|
65
|
+
5. If the design only needs a global shift in tone, density, spacing, width, radii, or typography, override tokens instead of writing new component CSS.
|
|
66
|
+
|
|
67
|
+
## Color themes
|
|
68
|
+
Minium ships 31 color themes in `dist/themes/`. Load one after the core stylesheet:
|
|
69
|
+
|
|
70
|
+
```html
|
|
71
|
+
<link rel="stylesheet" href="minium.min.css">
|
|
72
|
+
<link rel="stylesheet" href="themes/blue.css">
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
With npm: `import "@troennes/minium/themes/blue.css";`
|
|
76
|
+
|
|
77
|
+
Rules:
|
|
78
|
+
- A theme is named after its primary Radix scale: gray, mauve, slate, sage, olive, sand, bronze, gold, brown, orange (default), tomato, red, ruby, crimson, pink, plum, purple, violet, iris, indigo, blue, cyan, sky, teal, jade, green, grass, mint, lime, yellow, amber.
|
|
79
|
+
- Theme files declare the layer order and use `@layer theme`, so load order does not matter.
|
|
80
|
+
- Load one theme at a time.
|
|
81
|
+
|
|
82
|
+
Color roles:
|
|
83
|
+
- Semantic tokens reference seven roles, never scale names: `neutral`, `primary`, `accent`, `danger`, `success`, `warning`, `info`.
|
|
84
|
+
- Role tokens are named after Radix steps: `--neutral-1` … `--neutral-12`, `--primary-9`, `--primary-a5`, and so on. Each value is `light-dark(<light>, <dark>)`.
|
|
85
|
+
- `neutral` steps: 1, 2, 3, 4, 5, 8, 11, 12, a2–a7.
|
|
86
|
+
- Colored role steps: 7, 9, 10, 11, a2–a7, a11, plus `--<role>-text` (text color) and `--<role>-inverse` (text on the step 9 fill).
|
|
87
|
+
- To change a color, redefine every step of its role in `@layer theme`. A partly defined role mixes two colors.
|
|
88
|
+
- Bright scales (sky, mint, lime, yellow, amber) use `--<role>-text: light-dark(var(--neutral-12), var(--<role>-11))` and `--<role>-inverse: light-dark(var(--neutral-12), var(--neutral-1))`. Other scales use `var(--<role>-11)` and `white`.
|
|
89
|
+
- Use semantic tokens (`--color-primary`, `--color-danger-text`) in project CSS, not role steps, unless no semantic token fits.
|
|
90
|
+
|
|
91
|
+
## Adjusting one element with utilities
|
|
92
|
+
Token-bounded utility classes are the preferred way to tune one element. They map directly to a design token, so they stay inside the system. Use them instead of `style="--var: ..."` for one-offs.
|
|
93
|
+
|
|
94
|
+
Rules:
|
|
95
|
+
1. Reach for a utility before adding inline `style`.
|
|
96
|
+
2. Every utility is bounded to a token — there is no `gap-37px`. If you need an arbitrary value, use `style="--var: ..."` for a one-off, or define a project class for repeated patterns.
|
|
97
|
+
3. If you stack four or more utilities on the same element, promote it to a project class named for its intent.
|
|
98
|
+
4. Component-scoped escape valves (like `--sidebar-target-width`, `--switcher-breakpoint`, `--grid-min-size`, `--card-padding`, `--avatar-size`, `--n`/`--d` on `.frame`, alignment vars) do not have utility equivalents — for those, use `style="--var: ..."` or a project class.
|
|
99
|
+
|
|
100
|
+
Example: tighten and center a cluster
|
|
101
|
+
```html
|
|
102
|
+
<div class="cluster gap-2xs" style="--cluster-horizontal-alignment: center;">
|
|
103
|
+
<span class="badge">Docs</span>
|
|
104
|
+
<span class="badge">API</span>
|
|
105
|
+
<span class="badge">Guides</span>
|
|
106
|
+
</div>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Example: remove vertical spacing in a single flow container
|
|
110
|
+
```html
|
|
111
|
+
<article class="flow-none">
|
|
112
|
+
<h2>Compact panel</h2>
|
|
113
|
+
<p>No gap between direct children.</p>
|
|
114
|
+
</article>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Example: make grid items wider (no utility for `--grid-min-size`)
|
|
118
|
+
```html
|
|
119
|
+
<div class="grid gap-s" style="--grid-min-size: 14rem;">
|
|
120
|
+
<article class="card">One</article>
|
|
121
|
+
<article class="card">Two</article>
|
|
122
|
+
<article class="card">Three</article>
|
|
123
|
+
</div>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Example: reduce card padding (no utility for `--card-padding`)
|
|
127
|
+
```html
|
|
128
|
+
<article class="card" style="--card-padding: var(--space-s);">
|
|
129
|
+
<h2>Compact card</h2>
|
|
130
|
+
<p>Same component, denser interior spacing.</p>
|
|
131
|
+
</article>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Example: custom avatar size (no utility for `--avatar-size`)
|
|
135
|
+
```html
|
|
136
|
+
<figure class="avatar" style="--avatar-size: 5rem;">KC</figure>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Example: tune the sidebar split (no utility for `--sidebar-target-width`)
|
|
140
|
+
```html
|
|
141
|
+
<div class="sidebar" style="--sidebar-target-width: 8rem;">
|
|
142
|
+
<figure class="avatar">AB</figure>
|
|
143
|
+
<div class="flow">
|
|
144
|
+
<h2>Alex Brown</h2>
|
|
145
|
+
<p>Profile summary text.</p>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Project-specific CSS in `project.css`
|
|
151
|
+
Minium CSS is intentionally not meant to contain every possible app block or marketing pattern. When a UI need is specific to one product or repeats as a product-level pattern, put it in a project stylesheet such as `project.css`. Wrap all project.css code in `@layer project {...}`.
|
|
152
|
+
|
|
153
|
+
Use `project.css` for:
|
|
154
|
+
1. App-specific blocks like `.hero`, `.pricing-comparison`, `.dashboard-stat`, `.product-card`, or `.site-header`.
|
|
155
|
+
2. Small wrappers around Minium primitives where your project needs a named pattern.
|
|
156
|
+
3. Repeated utility stacks that should become a reusable project-level class.
|
|
157
|
+
4. Brand-specific presentation that should not become part of the shared Minium API.
|
|
158
|
+
|
|
159
|
+
Do not use `project.css` for:
|
|
160
|
+
1. Rewriting core Minium element defaults unless you truly want to replace the library behavior.
|
|
161
|
+
2. Creating a second utility framework.
|
|
162
|
+
3. Forking shared primitives when a token change or a utility class would solve the problem.
|
|
163
|
+
|
|
164
|
+
Recommended approach:
|
|
165
|
+
1. Start with semantic HTML and Minium defaults.
|
|
166
|
+
2. Add one or two Minium layout/component classes as needed.
|
|
167
|
+
3. Use token-bounded utilities for one-off adjustments.
|
|
168
|
+
4. Use `style="--var: ..."` only for component-scoped escape valves with no utility equivalent.
|
|
169
|
+
5. When the pattern becomes project-specific or reusable, promote it into `project.css`.
|
|
170
|
+
|
|
171
|
+
Example: project-level card variation
|
|
172
|
+
```css
|
|
173
|
+
.team-card {
|
|
174
|
+
--card-padding: var(--space-s);
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```html
|
|
179
|
+
<article class="card team-card">
|
|
180
|
+
<div class="sidebar media">
|
|
181
|
+
<figure class="avatar">KC</figure>
|
|
182
|
+
<div class="flow-tight">
|
|
183
|
+
<h2>Kim Carter</h2>
|
|
184
|
+
<p>Design systems engineer</p>
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
187
|
+
</article>
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Example: project hero built from Minium primitives
|
|
191
|
+
```css
|
|
192
|
+
.hero {
|
|
193
|
+
--flow-space: var(--flow-space-loose);
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
```html
|
|
198
|
+
<section class="hero flow container slim py-2xl">
|
|
199
|
+
<p class="eyebrow">New release</p>
|
|
200
|
+
<h1>Build semantic interfaces faster</h1>
|
|
201
|
+
<p class="lead">Minium CSS provides semantic defaults, layouts, and lightweight components.</p>
|
|
202
|
+
<div class="cluster gap-s">
|
|
203
|
+
<a href="#" role="button">Get started</a>
|
|
204
|
+
<a href="#" role="button" class="secondary">Read docs</a>
|
|
205
|
+
</div>
|
|
206
|
+
</section>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Integrations
|
|
210
|
+
1. Integrations are opt-in stylesheets that target markup produced by third-party tools (for example, Prism.js syntax tokens, Django form widgets). They ship alongside the core stylesheet, not inside it.
|
|
211
|
+
2. Each integration is its own file under `dist/integrations/`. Include only the ones you use, after `dist/minium.css`.
|
|
212
|
+
3. The core library styles HTML the user authors. Integrations style HTML produced by external tools. Anything tied to a specific JS library or framework belongs in the integration layer, not in core.
|
|
213
|
+
4. Integrations may consume core tokens (for example `--color-success` for diff insertions), but core never depends on an integration.
|
|
214
|
+
5. Integrations define their own tokens where they need colors that do not map onto Minium's semantic palette (for example syntax categories: `--keyword`, `--string`, `--comment`, `--function`, `--number`, `--constant`, `--operator`, `--tag`, `--punctuation`). They ship with light and dark variants of their own, independent of the main theme palette.
|
|
215
|
+
6. Available today: Django forms and Prism syntax highlighting. The Prism integration provides CSS only; the Prism.js library is a separate dependency the user installs.
|
|
216
|
+
7. The Django integration supports Django-rendered forms using the standard `{{ form }}` output or `{{ form.as_div }}`, which is Django's default div-based rendering style. It styles `.helptext`, `.errorlist`, and compact spacing inside unclassed field wrapper `div` elements.
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
## Semantic defaults
|
|
220
|
+
1. Plain text content is styled by default. Headings, paragraphs, lists, blockquotes, `hr`, inline text semantics, code, keyboard keys, sample output, captions, and tables all have built-in presentation.
|
|
221
|
+
2. Classless `main`, `article`, and `section` receive automatic vertical flow between direct children.
|
|
222
|
+
3. A top-level `header` and `footer` as direct children of `body` receive automatic page-shell styling, including sticky-footer behavior.
|
|
223
|
+
4. Navigation patterns are identified by context: a `nav` that is a direct child of `header` becomes a navbar, `aside > nav` becomes a side menu, and `aria-label="Breadcrumb"` / `aria-label="Pagination"` style those patterns.
|
|
224
|
+
5. Forms and fieldsets already provide consistent vertical rhythm for labels, controls, helper text, and actions.
|
|
225
|
+
6. Adding any class to a semantic section opts it out of default classless flow behavior, so you manage spacing manually (with `.flow` or utilities).
|
|
226
|
+
|
|
227
|
+
## Layout primitives
|
|
228
|
+
Layout primitives are small, composable structural classes. They share spacing tokens and nest freely. They are based on Every Layout and CUBE CSS Boilerplate.
|
|
229
|
+
|
|
230
|
+
### `.flow`
|
|
231
|
+
Use `.flow` on a parent to create consistent vertical spacing between direct children.
|
|
232
|
+
Default implementation: `.flow > * + * {margin-block-start: 1em}`
|
|
233
|
+
|
|
234
|
+
Rules:
|
|
235
|
+
- Adjust spacing with the `--flow-space` custom property, or use the utilities `.flow-tight`, `.flow-loose`, `.flow-none`.
|
|
236
|
+
- Built-in flow already exists on classless `main`, `article`, and `section`, and in all components such as cards, alerts, modals, and menus.
|
|
237
|
+
|
|
238
|
+
Example:
|
|
239
|
+
```html
|
|
240
|
+
<div class="flow">
|
|
241
|
+
<h2>Title</h2>
|
|
242
|
+
<p>Intro paragraph.</p>
|
|
243
|
+
<button>Continue</button>
|
|
244
|
+
</div>
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### `.cluster`
|
|
248
|
+
Use `.cluster` for horizontal groups that wrap naturally.
|
|
249
|
+
Default implementation uses horizontal flex and flex-wrap.
|
|
250
|
+
|
|
251
|
+
Rules:
|
|
252
|
+
- Good for tag rows, button toolbars, filters, compact metadata, and mixed inline controls.
|
|
253
|
+
- Children stay in a horizontal row until wrapping is needed.
|
|
254
|
+
- Tune gap with `gap-*` utilities.
|
|
255
|
+
- Tune alignment with `--cluster-horizontal-alignment` and `--cluster-vertical-alignment` (no utility equivalents).
|
|
256
|
+
|
|
257
|
+
Example:
|
|
258
|
+
```html
|
|
259
|
+
<div class="cluster gap-xs">
|
|
260
|
+
<button>All</button>
|
|
261
|
+
<button>Open</button>
|
|
262
|
+
<button>Closed</button>
|
|
263
|
+
</div>
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### `.container`
|
|
267
|
+
Use `.container` to center content and apply horizontal gutters and a maximum width.
|
|
268
|
+
|
|
269
|
+
Rules:
|
|
270
|
+
- `.container` is the default page-width wrapper.
|
|
271
|
+
- `.container.slim` is for narrower reading width.
|
|
272
|
+
- `.container.full` spans the available width without the standard max-width cap.
|
|
273
|
+
- Width behavior is driven by `--main-width` and `--content-width`.
|
|
274
|
+
|
|
275
|
+
Example:
|
|
276
|
+
```html
|
|
277
|
+
<main class="container slim">
|
|
278
|
+
<article>
|
|
279
|
+
<h1>Documentation</h1>
|
|
280
|
+
<p>Readable long-form content.</p>
|
|
281
|
+
</article>
|
|
282
|
+
</main>
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### `.grid`
|
|
286
|
+
Use `.grid` for responsive columns that wrap based on available space.
|
|
287
|
+
Default implementation uses `grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr))`.
|
|
288
|
+
|
|
289
|
+
Rules:
|
|
290
|
+
- Good for cards, feature lists, galleries, and evenly distributed blocks.
|
|
291
|
+
- Tune gap with `gap-*` utilities.
|
|
292
|
+
- Tune item width with `--grid-min-size` and `--grid-placement` (`auto-fill` or `auto-fit`).
|
|
293
|
+
- `.halves` and `.thirds` are preset variants for common column patterns. Halves give two columns and thirds give three when there is enough space.
|
|
294
|
+
|
|
295
|
+
Example:
|
|
296
|
+
```html
|
|
297
|
+
<div class="grid thirds gap-s">
|
|
298
|
+
<article>One</article>
|
|
299
|
+
<article>Two</article>
|
|
300
|
+
<article>Three</article>
|
|
301
|
+
</div>
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### `.repel`
|
|
305
|
+
Use `.repel` when content should push to opposite sides of a row.
|
|
306
|
+
Default implementation is horizontal flex with `justify-content: space-between`.
|
|
307
|
+
|
|
308
|
+
Rules:
|
|
309
|
+
- Good for action bars, list item controls, and summary rows.
|
|
310
|
+
- For page header navigation rows, prefer the semantic navbar pattern: `header > nav > ul`. A `nav` that is a direct child of `header` already behaves like a repelling row.
|
|
311
|
+
- Wrapping is supported by default. Add `.nowrap` to prevent wrapping.
|
|
312
|
+
- Tune gap with `gap-*` utilities.
|
|
313
|
+
- Use `--repel-vertical-alignment` for cross-axis alignment.
|
|
314
|
+
|
|
315
|
+
Example:
|
|
316
|
+
```html
|
|
317
|
+
<div class="repel">
|
|
318
|
+
<strong>Project</strong>
|
|
319
|
+
<a href="#">View details</a>
|
|
320
|
+
</div>
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### `.switcher`
|
|
324
|
+
Use `.switcher` for item groups that sit in a row when there is space and stack vertically when there is not.
|
|
325
|
+
|
|
326
|
+
Rules:
|
|
327
|
+
- Good for pricing tiers, summaries, comparison blocks, and mixed promo cards.
|
|
328
|
+
- Tune gap with `gap-*` utilities.
|
|
329
|
+
- Tune the stack threshold with `--switcher-breakpoint` (no utility equivalent).
|
|
330
|
+
- Tune cross-axis alignment with `--switcher-vertical-alignment`.
|
|
331
|
+
|
|
332
|
+
Example:
|
|
333
|
+
```html
|
|
334
|
+
<div class="switcher gap-s">
|
|
335
|
+
<section>Starter</section>
|
|
336
|
+
<section>Team</section>
|
|
337
|
+
<section>Enterprise</section>
|
|
338
|
+
</div>
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### `.sidebar`
|
|
342
|
+
Use `.sidebar` when one item should act like a narrow side column and the other like flexible content.
|
|
343
|
+
|
|
344
|
+
Rules:
|
|
345
|
+
- Good for media-object rows, profile summaries, avatar/content layouts, and documentation sidebars.
|
|
346
|
+
- Place exactly two children: the first is the sidebar, the second is the main content.
|
|
347
|
+
- Tune gap with `gap-*` utilities.
|
|
348
|
+
- Tune the side column with `--sidebar-target-width` and the stack threshold with `--sidebar-content-min-width` (no utility equivalents).
|
|
349
|
+
- Modifiers:
|
|
350
|
+
- `.reversed` — place the sidebar on the right.
|
|
351
|
+
- `.media` — lock the first child to its content size (avatar, icon, thumbnail beside text). This creates the typical media object layout.
|
|
352
|
+
- `.no-stretch` — do not stretch children to the same height.
|
|
353
|
+
|
|
354
|
+
Example:
|
|
355
|
+
```html
|
|
356
|
+
<div class="sidebar media">
|
|
357
|
+
<figure class="avatar">AB</figure>
|
|
358
|
+
<div class="flow">
|
|
359
|
+
<h2>Alex Brown</h2>
|
|
360
|
+
<p>Design systems engineer.</p>
|
|
361
|
+
</div>
|
|
362
|
+
</div>
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### `.frame`
|
|
366
|
+
Use `.frame` to keep media inside a fixed aspect ratio while cropping overflow cleanly.
|
|
367
|
+
|
|
368
|
+
Rules:
|
|
369
|
+
- Wrap a single `<img>` or `<video>` in a `<figure>` or `<div>` with `class="frame"`.
|
|
370
|
+
- Default ratio is 16:9. Override with `--n` (numerator) and `--d` (denominator).
|
|
371
|
+
- Media fills with `object-fit: cover`, so edges may be cropped to preserve the ratio.
|
|
372
|
+
|
|
373
|
+
Example:
|
|
374
|
+
```html
|
|
375
|
+
<figure class="frame" style="--n: 1; --d: 1;">
|
|
376
|
+
<img src="/photo.jpg" alt="Square thumbnail">
|
|
377
|
+
</figure>
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## Content patterns
|
|
381
|
+
|
|
382
|
+
### Typography
|
|
383
|
+
Minium CSS styles common document content by default.
|
|
384
|
+
|
|
385
|
+
Rules:
|
|
386
|
+
- Use semantic headings `h1` through `h6`.
|
|
387
|
+
- Use `hgroup` for a heading plus subtitle pair.
|
|
388
|
+
- `.eyebrow` is for small overline-style introductory text. It uses tiny upper-case text.
|
|
389
|
+
- `.lead` is for larger introductory paragraph text under a heading, also known as "lede".
|
|
390
|
+
- Lists, blockquotes, captions, `small`, `mark`, `ins`, `del`, `abbr`, `sub`, `sup`, and similar elements are already styled semantically.
|
|
391
|
+
|
|
392
|
+
### Code
|
|
393
|
+
Minium CSS styles code-related content without a separate component class.
|
|
394
|
+
|
|
395
|
+
Rules:
|
|
396
|
+
- Use `code` for inline code fragments.
|
|
397
|
+
- Use `kbd` for key labels.
|
|
398
|
+
- Use `samp` for command or program output.
|
|
399
|
+
- Use `<pre><code>` for code blocks.
|
|
400
|
+
- Code blocks get a distinct surface and horizontal scrolling automatically.
|
|
401
|
+
|
|
402
|
+
### Buttons
|
|
403
|
+
Buttons apply to native buttons (`<button>`), button-like inputs, and elements with `role="button"`.
|
|
404
|
+
|
|
405
|
+
Supported modifiers:
|
|
406
|
+
- Tone: `.accent`, `.danger`, `.success`, `.warning`, `.info`, `.contrast`, `.neutral`
|
|
407
|
+
- Emphasis: `.secondary`, `.tertiary`
|
|
408
|
+
- Size: `.small`, `.large`
|
|
409
|
+
- Width: `.full-width` (they are inline by default, unless they are in a form. In a form, buttons use 100% width.)
|
|
410
|
+
|
|
411
|
+
Behavior:
|
|
412
|
+
- Default button styling is the primary action style.
|
|
413
|
+
- `.secondary` is the quieter treatment: a soft tinted fill with colored text and no border. `input[type="reset"]` uses it by default.
|
|
414
|
+
- `.tertiary` is the lightest button treatment and looks like a link: text color with an underline. Tone classes only change the underline color, so use a solid or `.secondary` button for actions that must stand out, such as destructive ones.
|
|
415
|
+
- The `.full-width` utility makes the button fill the available width.
|
|
416
|
+
- Inside forms, action buttons are typically full width by default.
|
|
417
|
+
- `disabled` and `aria-disabled="true"` are supported.
|
|
418
|
+
- Wrap buttons in a `div role="group"` to join them into one connected row. Adjacent buttons get a divider line that contrasts in every theme and tone.
|
|
419
|
+
- Split button: inside a `role="group"`, put a `.dropdown` with an empty trigger after a button. The trigger shows only the chevron, takes the button look (not the transparent dropdown default), and joins the button with square inner corners. Give it an `aria-label`.
|
|
420
|
+
|
|
421
|
+
Example:
|
|
422
|
+
```html
|
|
423
|
+
<button class="accent">Save</button>
|
|
424
|
+
<button class="secondary">Preview</button>
|
|
425
|
+
<a href="/start" role="button" class="success large">Get started</a>
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
### Links
|
|
429
|
+
Plain links are styled semantically and support a few modifiers.
|
|
430
|
+
|
|
431
|
+
Supported modifiers:
|
|
432
|
+
- `.secondary`
|
|
433
|
+
- `.tertiary`
|
|
434
|
+
- `.accent`
|
|
435
|
+
- `.neutral`
|
|
436
|
+
|
|
437
|
+
Behavior:
|
|
438
|
+
- Use plain links for inline and navigational text actions.
|
|
439
|
+
- `.secondary` and `.tertiary` reduce default emphasis.
|
|
440
|
+
- `.accent` changes the link tone toward the accent color.
|
|
441
|
+
- `.neutral` keeps the link closer to surrounding text color.
|
|
442
|
+
- If the link should look and behave like a button, use `role="button"` and the button API instead.
|
|
443
|
+
|
|
444
|
+
### Tables
|
|
445
|
+
Tables are styled semantically.
|
|
446
|
+
|
|
447
|
+
Supported modifiers:
|
|
448
|
+
- `.striped` for banded body rows
|
|
449
|
+
- `.centered` for centered cell content
|
|
450
|
+
- `.border-none` to remove cell borders
|
|
451
|
+
- `.full-width` to make the table use the full width of the container
|
|
452
|
+
|
|
453
|
+
Behavior:
|
|
454
|
+
- Use semantic table structure with `caption`, `thead`, `tbody`, and `tfoot` when appropriate.
|
|
455
|
+
- Tables render as native `display: table` and size to their content. Use the `.full-width` utility to stretch a table to its container.
|
|
456
|
+
- For tables wider than the container, wrap the `table` in a `<div class="overflow-x">` to enable horizontal scrolling. Use either `.full-width` or `.overflow-x` based on whether columns can compress; combining them is rarely useful.
|
|
457
|
+
|
|
458
|
+
Example:
|
|
459
|
+
```html
|
|
460
|
+
<div class="overflow-x">
|
|
461
|
+
<table>...</table>
|
|
462
|
+
</div>
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
## Forms
|
|
466
|
+
|
|
467
|
+
### General form rules
|
|
468
|
+
1. Use native form markup with `label`, `input`, `textarea`, `select`, `fieldset`, `legend`, and buttons.
|
|
469
|
+
2. Helper text should be placed directly after the associated control.
|
|
470
|
+
3. Declare validation state on the control with `aria-invalid`; Minium does not validate the value or set the attribute for you.
|
|
471
|
+
4. Inside `form` and `fieldset`, Minium CSS already provides vertical spacing between controls and helper text.
|
|
472
|
+
|
|
473
|
+
### Show validation state
|
|
474
|
+
Minium styles the validation state declared by `aria-invalid` on an `input`, `textarea`, or `select`:
|
|
475
|
+
- Omit `aria-invalid` when the control has no explicit validation result. The control keeps its default styling.
|
|
476
|
+
- Set `aria-invalid="false"` to show an explicitly valid state.
|
|
477
|
+
- Set `aria-invalid="true"` to show an invalid state.
|
|
478
|
+
|
|
479
|
+
Set the attribute on the form control itself, including a checkbox, radio button, or switch. Text-like controls and textareas show a state icon. Controls use success or danger colors for their border and focus outline. Place a `small` element immediately after a text-like control, textarea, or select to explain the result; its text color follows the declared state.
|
|
480
|
+
|
|
481
|
+
Example:
|
|
482
|
+
```html
|
|
483
|
+
<label for="email">Email</label>
|
|
484
|
+
<input id="email" name="email" type="email" value="jane@" aria-invalid="true">
|
|
485
|
+
<small>Please enter a complete email address.</small>
|
|
486
|
+
|
|
487
|
+
<label for="terms">
|
|
488
|
+
<input id="terms" name="terms" type="checkbox" aria-invalid="false" checked>
|
|
489
|
+
Terms accepted
|
|
490
|
+
</label>
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### Text-like inputs
|
|
494
|
+
Supported input examples include:
|
|
495
|
+
- `text`
|
|
496
|
+
- `email`
|
|
497
|
+
- `number`
|
|
498
|
+
- `password`
|
|
499
|
+
- `tel`
|
|
500
|
+
- `url`
|
|
501
|
+
- `search`
|
|
502
|
+
- `date`
|
|
503
|
+
- `datetime-local`
|
|
504
|
+
- `month`
|
|
505
|
+
- `time`
|
|
506
|
+
- `color`
|
|
507
|
+
- `file`
|
|
508
|
+
- `range`
|
|
509
|
+
- `button`
|
|
510
|
+
- `submit`
|
|
511
|
+
- `reset`
|
|
512
|
+
|
|
513
|
+
Behavior:
|
|
514
|
+
- All text-like controls fill the available width by default.
|
|
515
|
+
- Use `disabled` and `readonly` where appropriate.
|
|
516
|
+
- Use `fieldset role="group"` for compact combined controls such as a search field plus submit action.
|
|
517
|
+
- A `fieldset` shows a border and legend by default; `role="group"` or a layout class removes the box, and `.bare` removes it explicitly while keeping field spacing.
|
|
518
|
+
|
|
519
|
+
### `textarea`
|
|
520
|
+
Behavior:
|
|
521
|
+
- Use a native `textarea` with a label.
|
|
522
|
+
- It fills the available width and allows vertical resizing.
|
|
523
|
+
- `.small` and `.large` are supported size modifiers.
|
|
524
|
+
|
|
525
|
+
### `select`
|
|
526
|
+
Behavior:
|
|
527
|
+
- Use a native `select` with a label.
|
|
528
|
+
- `multiple` and `optgroup` are supported as normal HTML features.
|
|
529
|
+
- `.small` and `.large` are supported size modifiers.
|
|
530
|
+
|
|
531
|
+
### `checkbox`
|
|
532
|
+
Behavior:
|
|
533
|
+
- For stacked (vertical) forms, the simplest pattern is wrapping the input inside the label.
|
|
534
|
+
- For inline (horizontal) groups, use adjacent `input + label`.
|
|
535
|
+
- Use `fieldset` to group related options.
|
|
536
|
+
|
|
537
|
+
### `radio`
|
|
538
|
+
Behavior:
|
|
539
|
+
- Use `input type="radio"` with the same `name` for one-of-many choices.
|
|
540
|
+
- For inline groups, use adjacent `input + label`.
|
|
541
|
+
- Use `fieldset` and `legend` when the set answers one named question.
|
|
542
|
+
|
|
543
|
+
### `switch`
|
|
544
|
+
Behavior:
|
|
545
|
+
- Use `input type="checkbox" role="switch"` for on/off settings.
|
|
546
|
+
- For inline groups, use adjacent `input + label`.
|
|
547
|
+
- Use `fieldset` and `legend` for grouped switch settings.
|
|
548
|
+
|
|
549
|
+
## Components
|
|
550
|
+
|
|
551
|
+
### Accordion
|
|
552
|
+
Accordions use the native `details` and `summary` pattern.
|
|
553
|
+
|
|
554
|
+
Behavior:
|
|
555
|
+
- Wrap each panel in `details`.
|
|
556
|
+
- Use `summary` as the interactive heading.
|
|
557
|
+
- Put the panel content immediately after `summary`.
|
|
558
|
+
- Give every `summary` a visible, non-empty label.
|
|
559
|
+
- Use `open` on `details` to make a panel expanded by default.
|
|
560
|
+
- Use the same `name` on multiple `details` when only one panel should be open at a time.
|
|
561
|
+
- Wrap multiple accordions in a container with `role="group"` if they should look like one connected set.
|
|
562
|
+
- Add `role="button"` to `summary` if you want it to inherit button styling.
|
|
563
|
+
- Add `.border-none` to `details` if the standard framed panel look should be removed.
|
|
564
|
+
|
|
565
|
+
Example:
|
|
566
|
+
```html
|
|
567
|
+
<details>
|
|
568
|
+
<summary>What is Minium CSS?</summary>
|
|
569
|
+
<p>Minium CSS is a semantic-first CSS library.</p>
|
|
570
|
+
</details>
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
### Alert
|
|
574
|
+
Use `.alert` for inline feedback and status messages.
|
|
575
|
+
|
|
576
|
+
Supported modifiers:
|
|
577
|
+
- `.primary`
|
|
578
|
+
- `.accent`
|
|
579
|
+
- `.info`
|
|
580
|
+
- `.warning`
|
|
581
|
+
- `.success`
|
|
582
|
+
- `.danger`
|
|
583
|
+
|
|
584
|
+
Behavior:
|
|
585
|
+
- Add `.alert` to a container.
|
|
586
|
+
- Use `role="alert"` for urgent announcements that assistive tech should treat assertively.
|
|
587
|
+
- Alerts support rich internal content such as headings, paragraphs, and actions.
|
|
588
|
+
- Alerts already include internal flow spacing between direct children.
|
|
589
|
+
- A `.close` button as the last direct child is pinned in the top inline-end corner, and the alert reserves space for it. Dismissing needs one line of JavaScript. A `.close` nested in a wrapper (such as a `.repel` row) stays in normal flow.
|
|
590
|
+
|
|
591
|
+
Example:
|
|
592
|
+
```html
|
|
593
|
+
<div class="alert warning" role="alert">
|
|
594
|
+
Your trial ends in 2 days.
|
|
595
|
+
</div>
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
Dismissable example:
|
|
599
|
+
```html
|
|
600
|
+
<div class="alert info">
|
|
601
|
+
<h3>New documentation available</h3>
|
|
602
|
+
<p>Review the updated guidelines before the next release.</p>
|
|
603
|
+
<button class="close" aria-label="Dismiss" onclick="this.closest('.alert').remove()"></button>
|
|
604
|
+
</div>
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
### Avatar
|
|
608
|
+
Use `.avatar` for compact user images or initials.
|
|
609
|
+
|
|
610
|
+
Supported modifiers:
|
|
611
|
+
- Size: `.small` or `.large`
|
|
612
|
+
- Shape: `.square` or `.squircle` (circle is default)
|
|
613
|
+
|
|
614
|
+
Behavior:
|
|
615
|
+
- Use a `figure` with `.avatar`.
|
|
616
|
+
- Place an `img` inside for a photo avatar.
|
|
617
|
+
- Plain text inside the avatar acts as initials fallback.
|
|
618
|
+
- Use `--avatar-size` for custom sizing without creating a new size modifier.
|
|
619
|
+
- Wrap multiple avatars in a container with `role="group"` for overlapping avatar groups.
|
|
620
|
+
|
|
621
|
+
Example:
|
|
622
|
+
```html
|
|
623
|
+
<figure class="avatar">
|
|
624
|
+
<img src="/user.jpg" alt="Ava Carter">
|
|
625
|
+
</figure>
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### Badge and Pill
|
|
629
|
+
Use `.badge` and `.pill` for small labels, status chips, and metadata markers.
|
|
630
|
+
|
|
631
|
+
Supported modifiers:
|
|
632
|
+
- `.primary`
|
|
633
|
+
- `.accent`
|
|
634
|
+
- `.info`
|
|
635
|
+
- `.success`
|
|
636
|
+
- `.warning`
|
|
637
|
+
- `.danger`
|
|
638
|
+
- `.muted`
|
|
639
|
+
|
|
640
|
+
Behavior:
|
|
641
|
+
- `.badge` is the default rounded-rectangle style.
|
|
642
|
+
- `.pill` is the fully rounded style.
|
|
643
|
+
- They can be used on `span`, `a`, or `button`.
|
|
644
|
+
- Interactive badges and pills get hover/focus behavior automatically.
|
|
645
|
+
- Only use one modifier as they cannot be combined
|
|
646
|
+
|
|
647
|
+
Example:
|
|
648
|
+
```html
|
|
649
|
+
<span class="badge success">Active</span>
|
|
650
|
+
<a href="#" class="pill accent">Upgrade</a>
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
### Icon
|
|
654
|
+
Use `.icon` to size an inline SVG to match surrounding text.
|
|
655
|
+
|
|
656
|
+
Behavior:
|
|
657
|
+
- Minium does not include an icon set. Users choose their own SVG icons.
|
|
658
|
+
- Docs examples commonly use Lucide inline SVGs, but Lucide is not a dependency.
|
|
659
|
+
- Some Minium controls use internal CSS mask icons for component UI; those tokens are not a general icon library.
|
|
660
|
+
- `.icon` is a 1em square and is baseline-aligned.
|
|
661
|
+
- Icons follow text color when the SVG uses `currentColor`.
|
|
662
|
+
- Because sizing is em-based, plain `.icon` should be used most of the time.
|
|
663
|
+
- Use `.icon.small` or `.icon.large` only when an icon should be smaller or larger than the surrounding text.
|
|
664
|
+
- `--icon-size` and `--icon-align` can be scoped to one icon or to the smallest wrapper that should affect its child icons.
|
|
665
|
+
|
|
666
|
+
Example:
|
|
667
|
+
```html
|
|
668
|
+
<svg class="icon" aria-hidden="true" viewBox="0 0 24 24">
|
|
669
|
+
...
|
|
670
|
+
</svg>
|
|
671
|
+
|
|
672
|
+
<svg class="icon large" aria-hidden="true" viewBox="0 0 24 24">
|
|
673
|
+
...
|
|
674
|
+
</svg>
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
### Breadcrumb
|
|
678
|
+
Breadcrumbs are styled through semantic navigation.
|
|
679
|
+
|
|
680
|
+
Behavior:
|
|
681
|
+
- Use `nav aria-label="Breadcrumb"`.
|
|
682
|
+
- Use `ol` inside the nav.
|
|
683
|
+
- Mark the current page with `aria-current="page"`. The last item is usually plain text, so it sits on the `li`; if the current page links to itself, put it on the `a` instead.
|
|
684
|
+
|
|
685
|
+
Example:
|
|
686
|
+
```html
|
|
687
|
+
<nav aria-label="Breadcrumb">
|
|
688
|
+
<ol>
|
|
689
|
+
<li><a href="/">Home</a></li>
|
|
690
|
+
<li><a href="/docs" aria-current="page">Docs</a></li>
|
|
691
|
+
</ol>
|
|
692
|
+
</nav>
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
### Card
|
|
696
|
+
Use `.card` for a raised container with border, radius, shadow, and built-in internal spacing.
|
|
697
|
+
|
|
698
|
+
Behavior:
|
|
699
|
+
- Use it on `article`, `section`, `div`, or sometimes `a`.
|
|
700
|
+
- Optionally use `--card-padding` to customize internal padding and density.
|
|
701
|
+
- Direct child `header` and `footer` become card sections with separators.
|
|
702
|
+
- A direct child `figure` bleeds edge-to-edge by default.
|
|
703
|
+
- Add `.inset` to a direct child `figure` when the media should stay inside the card padding.
|
|
704
|
+
- Cards already provide internal flow spacing, so extra `.flow` is often unnecessary.
|
|
705
|
+
|
|
706
|
+
Link cards:
|
|
707
|
+
- Use `a.card` to make the whole card one link. It shows hover/active feedback, and text inside keeps normal card styling (no link color or underline).
|
|
708
|
+
- Do not nest links, buttons, or other interactive elements inside a link card.
|
|
709
|
+
|
|
710
|
+
Example:
|
|
711
|
+
```html
|
|
712
|
+
<article class="card">
|
|
713
|
+
<h2>Card title</h2>
|
|
714
|
+
<p>Supporting text.</p>
|
|
715
|
+
</article>
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
Example: link card
|
|
719
|
+
```html
|
|
720
|
+
<a href="/post" class="card">
|
|
721
|
+
<h2>Card title</h2>
|
|
722
|
+
<p>Supporting text.</p>
|
|
723
|
+
</a>
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
### Dropdown
|
|
727
|
+
Dropdowns use the native Popover API and CSS anchor positioning. Projects targeting browsers without those features should provide polyfills.
|
|
728
|
+
|
|
729
|
+
Behavior:
|
|
730
|
+
- Wrap the whole pattern in `.dropdown`.
|
|
731
|
+
- Use a trigger element with `popovertarget`.
|
|
732
|
+
- Use a popover panel element with a matching `id` and the `popover` attribute.
|
|
733
|
+
- Use a generic container (such as `div`) as the popover panel for action lists. Use `nav` only when the panel contains navigation links, and label it with `aria-label` or `aria-labelledby`.
|
|
734
|
+
- Button variants can also be used on the trigger.
|
|
735
|
+
- Icon-only triggers should use `.icon-only` and an accessible name such as `aria-label`; mark the decorative SVG with `aria-hidden="true"`.
|
|
736
|
+
- The panel is anchored to the trigger via CSS anchor positioning and flips block/inline to stay in the viewport.
|
|
737
|
+
- Inside a `role="group"` after a button, a dropdown forms a split button: the trigger takes the button look, joins the button before it, and an empty trigger shows only the chevron (give it an `aria-label`).
|
|
738
|
+
|
|
739
|
+
Accessibility:
|
|
740
|
+
- Dropdowns are native popovers, not full ARIA menu buttons (no `role="menu"`, `aria-expanded`, or focus management — the APG menu button pattern requires JavaScript).
|
|
741
|
+
- Keyboard: Enter/Space opens the popover, Tab moves through items, Escape or light dismiss closes it. Arrow-key navigation is not provided since it would require JavaScript.
|
|
742
|
+
|
|
743
|
+
Modifiers (on `.dropdown`):
|
|
744
|
+
- `.border-none` — removes the trigger button's border and shadow.
|
|
745
|
+
- `.left` — aligns the panel to the trigger's left edge.
|
|
746
|
+
- `.center` — centers the panel under the trigger.
|
|
747
|
+
- Default alignment is to the trigger's right edge.
|
|
748
|
+
|
|
749
|
+
Width custom properties (set on `.dropdown` or any ancestor):
|
|
750
|
+
- `--dropdown-width` — panel `inline-size`. Default `max-content`.
|
|
751
|
+
- `--dropdown-min-width` — panel `min-inline-size`. Default `12rem`.
|
|
752
|
+
- `--dropdown-max-width` — panel `max-inline-size`. Default `calc(100% - var(--space-s-l))`.
|
|
753
|
+
|
|
754
|
+
Nesting:
|
|
755
|
+
- A `.dropdown` may be placed inside another dropdown's panel.
|
|
756
|
+
|
|
757
|
+
Split button example:
|
|
758
|
+
```html
|
|
759
|
+
<div role="group">
|
|
760
|
+
<button>Save</button>
|
|
761
|
+
<div class="dropdown">
|
|
762
|
+
<button popovertarget="save-menu" aria-label="More save options"></button>
|
|
763
|
+
<div id="save-menu" popover>
|
|
764
|
+
<ul>
|
|
765
|
+
<li><a href="#">Save as draft</a></li>
|
|
766
|
+
<li><a href="#">Save and publish</a></li>
|
|
767
|
+
</ul>
|
|
768
|
+
</div>
|
|
769
|
+
</div>
|
|
770
|
+
</div>
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
Example:
|
|
774
|
+
```html
|
|
775
|
+
<div class="dropdown">
|
|
776
|
+
<button popovertarget="menu-1">Menu</button>
|
|
777
|
+
<div id="menu-1" popover>
|
|
778
|
+
<ul>
|
|
779
|
+
<li><a href="#">Profile</a></li>
|
|
780
|
+
<li>
|
|
781
|
+
<div class="dropdown">
|
|
782
|
+
<button popovertarget="nested-menu-1">Share</button>
|
|
783
|
+
<div id="nested-menu-1" popover>
|
|
784
|
+
<ul>
|
|
785
|
+
<li><a href="#">Copy link</a></li>
|
|
786
|
+
<li><a href="#">Email</a></li>
|
|
787
|
+
</ul>
|
|
788
|
+
</div>
|
|
789
|
+
</div>
|
|
790
|
+
</li>
|
|
791
|
+
<li><button>Sign out</button></li>
|
|
792
|
+
</ul>
|
|
793
|
+
</div>
|
|
794
|
+
</div>
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
### Modal
|
|
798
|
+
Modals use native `dialog`.
|
|
799
|
+
|
|
800
|
+
Behavior:
|
|
801
|
+
- Use a `dialog` element for dialog content.
|
|
802
|
+
- Open with `showModal()` for a true modal dialog: the outside page becomes inert and focus is trapped inside.
|
|
803
|
+
- Add `popover` and open with `popovertarget` for a non-modal dialog: no JavaScript needed, but the outside page stays interactive and focus can leave it. Scroll-locking while open is visual only and does not make the page inert.
|
|
804
|
+
- Give every dialog an accessible name via `aria-labelledby` (pointing at a visible title) or `aria-label`.
|
|
805
|
+
- Use `<form method="dialog">` for simple confirm/cancel flows so buttons close the dialog without JavaScript.
|
|
806
|
+
- Direct child `header` and `footer` create structured sections similar to a card.
|
|
807
|
+
- Modals already provide internal flow spacing, so extra `.flow` is often unnecessary.
|
|
808
|
+
- A `.close` button as the last direct child of the dialog is pinned in the top inline-end corner, and the dialog keeps the title row clear of it. Keep it a direct child even when content is wrapped in an `article`. For `showModal()` dialogs wrap it in `<form method="dialog">` (the wrapper takes no space); for popover dialogs use `popovertarget` with `popovertargetaction="hide"`.
|
|
809
|
+
|
|
810
|
+
Example:
|
|
811
|
+
```html
|
|
812
|
+
<dialog id="confirm-dialog" aria-labelledby="confirm-dialog-title">
|
|
813
|
+
<header><strong id="confirm-dialog-title">Confirm delete</strong></header>
|
|
814
|
+
<p>This action cannot be undone.</p>
|
|
815
|
+
<footer>
|
|
816
|
+
<form method="dialog" class="cluster" style="--cluster-horizontal-alignment: flex-end;">
|
|
817
|
+
<button class="secondary">Cancel</button>
|
|
818
|
+
<button class="danger">Delete</button>
|
|
819
|
+
</form>
|
|
820
|
+
</footer>
|
|
821
|
+
<form method="dialog">
|
|
822
|
+
<button class="close" aria-label="Close"></button>
|
|
823
|
+
</form>
|
|
824
|
+
</dialog>
|
|
825
|
+
<button type="button" onclick="document.getElementById('confirm-dialog').showModal()">Delete…</button>
|
|
826
|
+
```
|
|
827
|
+
|
|
828
|
+
### Navbar
|
|
829
|
+
The navbar pattern applies to a `nav` that is a direct child of a `header`, or to any `nav` with the `.navbar` class.
|
|
830
|
+
|
|
831
|
+
Behavior:
|
|
832
|
+
- Place the `nav` as a direct child of a `header` (typical page-header position) — no class needed.
|
|
833
|
+
- Outside a header, add `.navbar` to the `nav`.
|
|
834
|
+
- Use one or more direct child `ul` groups inside the `nav`.
|
|
835
|
+
- The `nav` behaves like a repelling row.
|
|
836
|
+
- Each direct child `ul` behaves like a horizontal cluster.
|
|
837
|
+
- If the page header constrains content width, put `.container` on the `nav` itself (`<header><nav class="container">`) so the `nav` stays a direct child of the `header`.
|
|
838
|
+
- To always keep a navbar at the top of its scroll container, add `.sticky` to the `header` in the semantic pattern or to a standalone `nav.navbar`. The modifier sets `position: sticky`, `top: 0`, and `z-index: 1020`. It does not affect other elements.
|
|
839
|
+
- Do not use this pattern for side menus, breadcrumbs, or pagination.
|
|
840
|
+
- A `nav` outside a header and without `.navbar` gets only shared nav basics (no list bullets, links inherit text color).
|
|
841
|
+
|
|
842
|
+
Example:
|
|
843
|
+
```html
|
|
844
|
+
<header>
|
|
845
|
+
<nav>
|
|
846
|
+
<ul>
|
|
847
|
+
<li><strong>Acme</strong></li>
|
|
848
|
+
</ul>
|
|
849
|
+
<ul>
|
|
850
|
+
<li><a href="#">Docs</a></li>
|
|
851
|
+
<li><a href="#" role="button">Start</a></li>
|
|
852
|
+
</ul>
|
|
853
|
+
</nav>
|
|
854
|
+
</header>
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
Example: navbar outside a header
|
|
858
|
+
```html
|
|
859
|
+
<nav class="navbar">
|
|
860
|
+
<ul>
|
|
861
|
+
<li><strong>Acme</strong></li>
|
|
862
|
+
</ul>
|
|
863
|
+
<ul>
|
|
864
|
+
<li><a href="#">Docs</a></li>
|
|
865
|
+
</ul>
|
|
866
|
+
</nav>
|
|
867
|
+
```
|
|
868
|
+
|
|
869
|
+
Example: sticky navbar
|
|
870
|
+
```html
|
|
871
|
+
<header class="sticky">
|
|
872
|
+
<nav class="container">...</nav>
|
|
873
|
+
</header>
|
|
874
|
+
|
|
875
|
+
<nav class="navbar sticky">...</nav>
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
### Side menu
|
|
879
|
+
The side menu pattern is semantic markup inside `aside`.
|
|
880
|
+
|
|
881
|
+
Supported states:
|
|
882
|
+
- `[aria-current]`
|
|
883
|
+
- `[aria-disabled="true"]`
|
|
884
|
+
|
|
885
|
+
Behavior:
|
|
886
|
+
- Use `aside > nav > ul`.
|
|
887
|
+
- Label the `nav` with `aria-label` (or `aria-labelledby`) so it is distinct from other nav landmarks; the `aside > nav` selector still applies.
|
|
888
|
+
- Nest `ul` inside list items for hierarchy.
|
|
889
|
+
- Use `aria-current="page"` on the current link (not the `li`) so the state is announced with the link.
|
|
890
|
+
- Use `aria-disabled="true"` on unavailable items.
|
|
891
|
+
- Use `li > hr` for a thematic break; `hr` already has separator semantics (no `role="separator"`).
|
|
892
|
+
- `details` and `summary` can be used for collapsible menu sections (dropdown component).
|
|
893
|
+
- Buttons, links, and summaries inside the menu inherit shared menu-item styling.
|
|
894
|
+
- A plain `<aside>` stays its natural size — suitable for tables of contents, related-content panels, and inline callouts.
|
|
895
|
+
- For a full-height side menu, add `.full-height` to the `<aside>` to fill the viewport, scroll a long inner `<nav>`, and pin a child `<footer>` to the bottom. This class controls sizing and internal overflow; it does not make the side menu sticky. Define sticky page-shell behavior with the shell's responsive rules in `@layer project`.
|
|
896
|
+
|
|
897
|
+
Example:
|
|
898
|
+
```html
|
|
899
|
+
<aside>
|
|
900
|
+
<nav aria-label="Documentation">
|
|
901
|
+
<ul>
|
|
902
|
+
<li><a href="#" aria-current="page">Overview</a></li>
|
|
903
|
+
<li><a href="#">Settings</a></li>
|
|
904
|
+
</ul>
|
|
905
|
+
</nav>
|
|
906
|
+
</aside>
|
|
907
|
+
```
|
|
908
|
+
|
|
909
|
+
Full-height variant:
|
|
910
|
+
```html
|
|
911
|
+
<aside class="full-height">
|
|
912
|
+
<header>Workspace</header>
|
|
913
|
+
<nav aria-label="Workspace">
|
|
914
|
+
<ul>
|
|
915
|
+
<li><a href="#" aria-current="page">Overview</a></li>
|
|
916
|
+
<li><a href="#">Settings</a></li>
|
|
917
|
+
</ul>
|
|
918
|
+
</nav>
|
|
919
|
+
<footer>Account</footer>
|
|
920
|
+
</aside>
|
|
921
|
+
```
|
|
922
|
+
|
|
923
|
+
### Skeleton
|
|
924
|
+
Use `.skeleton` for loading placeholders.
|
|
925
|
+
|
|
926
|
+
Supported shapes:
|
|
927
|
+
- `.line`
|
|
928
|
+
- `.box`
|
|
929
|
+
- `.circle`
|
|
930
|
+
|
|
931
|
+
Behavior:
|
|
932
|
+
- Add `.skeleton` plus one shape class.
|
|
933
|
+
- Use `aria-hidden="true"` on the placeholder itself.
|
|
934
|
+
- Put `aria-busy="true"` on the stable region being updated (the container that will hold the real content), then clear it (set `false` or remove) when content loads.
|
|
935
|
+
- The shimmer effect is reduced automatically when reduced-motion is requested.
|
|
936
|
+
|
|
937
|
+
Example:
|
|
938
|
+
```html
|
|
939
|
+
<article aria-busy="true">
|
|
940
|
+
<div class="skeleton line" aria-hidden="true"></div>
|
|
941
|
+
<div class="skeleton box" aria-hidden="true"></div>
|
|
942
|
+
</article>
|
|
943
|
+
```
|
|
944
|
+
|
|
945
|
+
### Tabs
|
|
946
|
+
Tabs links are styled on semantic navigation with the `.tabs` class. The strip renders as a horizontal row of links with a clear current state and an underline indicator.
|
|
947
|
+
|
|
948
|
+
Behavior:
|
|
949
|
+
- Use `nav class="tabs" aria-label="..."` with a descriptive label.
|
|
950
|
+
- Inside, use a plain `ul` of list items.
|
|
951
|
+
- Each item may contain a link (`a`) for tabs that navigate, or a `button` for tabs that switch panels in place.
|
|
952
|
+
- Mark the current tab with `aria-current="page"` on its link or button (not the `li`).
|
|
953
|
+
- Icons inside a tab inherit the link's text color, including the current state.
|
|
954
|
+
- Minium ships CSS only. The strip styles the navigation, but switching panels in place requires your own mechanism — either routing (one URL per tab) or your own JavaScript. This is not a full ARIA Tabs widget, so do not claim managed-keyboard accessibility parity with a JavaScript widget.
|
|
955
|
+
|
|
956
|
+
Example:
|
|
957
|
+
```html
|
|
958
|
+
<nav class="tabs" aria-label="Animals">
|
|
959
|
+
<ul>
|
|
960
|
+
<li><a href="#" aria-current="page">Snow leopard</a></li>
|
|
961
|
+
<li><a href="#">Honey bee</a></li>
|
|
962
|
+
<li><a href="#">Elephant</a></li>
|
|
963
|
+
</ul>
|
|
964
|
+
</nav>
|
|
965
|
+
```
|
|
966
|
+
|
|
967
|
+
### Progress and meter
|
|
968
|
+
Minium CSS styles native `<progress>` and `<meter>`.
|
|
969
|
+
|
|
970
|
+
Behavior:
|
|
971
|
+
- Use `progress` for completion state such as uploads or loading.
|
|
972
|
+
- Use `meter` for measured values within a known range.
|
|
973
|
+
- Indeterminate progress bars animate unless reduced motion is requested.
|
|
974
|
+
- `meter` color shifts according to its semantic range values.
|
|
975
|
+
- Give every `progress` and `meter` an accessible name. Associate a visible `label` (via `for`/`id`), or use `aria-label`/`aria-labelledby` when no visible label fits.
|
|
976
|
+
|
|
977
|
+
Example:
|
|
978
|
+
```html
|
|
979
|
+
<label for="upload-progress">Uploading</label>
|
|
980
|
+
<progress id="upload-progress" value="43" max="100">43%</progress>
|
|
981
|
+
|
|
982
|
+
<label for="disk-meter">Disk usage</label>
|
|
983
|
+
<meter id="disk-meter" min="0" max="100" low="30" high="80" optimum="100" value="72">72%</meter>
|
|
984
|
+
```
|
|
985
|
+
|
|
986
|
+
### Pagination
|
|
987
|
+
Pagination is styled through semantic navigation.
|
|
988
|
+
|
|
989
|
+
Supported states:
|
|
990
|
+
- `aria-disabled="true"`
|
|
991
|
+
- `aria-current="page"`
|
|
992
|
+
|
|
993
|
+
Behavior:
|
|
994
|
+
- Use `nav aria-label="Pagination"`.
|
|
995
|
+
- Use a plain `ul` inside.
|
|
996
|
+
- Mark the current page with `aria-current="page"` on its link or button (not the `li`).
|
|
997
|
+
- Use `aria-disabled="true"` for unavailable controls.
|
|
998
|
+
- Anchors, buttons, and button/link roles can be mixed as items if needed.
|
|
999
|
+
|
|
1000
|
+
Example:
|
|
1001
|
+
```html
|
|
1002
|
+
<nav aria-label="Pagination">
|
|
1003
|
+
<ul>
|
|
1004
|
+
<li><span aria-disabled="true">Previous</span></li>
|
|
1005
|
+
<li><a href="#" aria-current="page">1</a></li>
|
|
1006
|
+
<li><a href="#">2</a></li>
|
|
1007
|
+
<li><a href="#">Next</a></li>
|
|
1008
|
+
</ul>
|
|
1009
|
+
</nav>
|
|
1010
|
+
```
|
|
1011
|
+
|
|
1012
|
+
### Tooltip
|
|
1013
|
+
Tooltips use a CSS-only pattern driven by data attributes.
|
|
1014
|
+
|
|
1015
|
+
Attributes:
|
|
1016
|
+
- `data-tooltip="..."` — the tooltip text (required).
|
|
1017
|
+
- `data-placement="..."` — placement: `top` (default), `right`, `bottom`, or `left`.
|
|
1018
|
+
|
|
1019
|
+
Behavior:
|
|
1020
|
+
- Add `data-tooltip` to the target element with the tooltip text as its value.
|
|
1021
|
+
- Set `data-placement` if you need a side other than the default top.
|
|
1022
|
+
- For non-interactive inline elements, add `tabindex="0"` if keyboard users should be able to focus and reveal the tooltip.
|
|
1023
|
+
- Long tooltip text near viewport edges is not fully handled, so keep tooltip content short.
|
|
1024
|
+
- `data-tooltip` is visual only and not exposed to assistive tech; if it is the element's only label, also provide an accessible name (e.g. `aria-label`).
|
|
1025
|
+
|
|
1026
|
+
Example:
|
|
1027
|
+
```html
|
|
1028
|
+
<button data-tooltip="Delete item" data-placement="top">
|
|
1029
|
+
Delete
|
|
1030
|
+
</button>
|
|
1031
|
+
```
|
|
1032
|
+
|
|
1033
|
+
## Utilities
|
|
1034
|
+
Utilities are token-bounded shortcuts: each one maps directly to a design token. Prefer them over inline `style="--var: ..."` for one-off adjustments. Every value comes from the theme scale, so utilities cannot drift outside the design system. Do not compose components with utility classes, create a project layer class instead.
|
|
1035
|
+
|
|
1036
|
+
### Spacing
|
|
1037
|
+
All spacing utilities use the `--space-*` scale: `3xs`, `2xs`, `xs`, `s`, `m`, `l`, `xl`, `2xl`, `3xl`. A `-0` reset is also available on each axis.
|
|
1038
|
+
|
|
1039
|
+
- Gap: `.gap-0`, `.gap-3xs` … `.gap-3xl`
|
|
1040
|
+
- Margin: `.m-0`, `.m-3xs` … `.m-3xl`; inline: `.mx-0`, `.mx-auto`, `.mx-3xs` … `.mx-3xl`; block: `.my-0`, `.my-3xs` … `.my-3xl`
|
|
1041
|
+
- Padding: `.p-0`, `.p-3xs` … `.p-3xl`; inline: `.px-0`, `.px-3xs` … `.px-3xl`; block: `.py-0`, `.py-3xs` … `.py-3xl`
|
|
1042
|
+
|
|
1043
|
+
### Color
|
|
1044
|
+
- Surface backgrounds: `.bg-sunken`, `.bg-surface`, `.bg-raised`, `.bg-overlay`, `.bg-fill`, `.bg-transparent`, `.bg-contrast`
|
|
1045
|
+
- Semantic background alpha fills: `.bg-primary`, `.bg-accent`, `.bg-success`, `.bg-danger`, `.bg-warning`, `.bg-info`
|
|
1046
|
+
- Foreground text colors: `.fg-primary`, `.fg-accent`, `.fg-success`, `.fg-danger`, `.fg-warning`, `.fg-info`, `.fg-muted`
|
|
1047
|
+
|
|
1048
|
+
### Typography
|
|
1049
|
+
- Size: `.size-h1`, `.size-h2`, `.size-h3`, `.size-h4`, `.size-body`, `.size-small`, `.size-tiny`
|
|
1050
|
+
- Weight: `.weight-normal`, `.weight-bold`
|
|
1051
|
+
|
|
1052
|
+
### Borders and radius
|
|
1053
|
+
- Border: `.border-none`, `.border-weak`, `.border-strong`
|
|
1054
|
+
- Radius: `.radius-0`, `.radius-s`, `.radius-m`, `.radius-l`, `.radius-f`, plus `.rounded` (alias for `radius-f`)
|
|
1055
|
+
|
|
1056
|
+
### Shadow
|
|
1057
|
+
`.shadow-none`, `.shadow-s`, `.shadow-m`, `.shadow-l`, `.shadow-inner`
|
|
1058
|
+
|
|
1059
|
+
### Flow space
|
|
1060
|
+
Override vertical rhythm inside any flow container (`.flow`, classless `main`/`article`/`section`, `.card`, etc.):
|
|
1061
|
+
`.flow-glue`, `.flow-tight`, `.flow-loose`, `.flow-none`
|
|
1062
|
+
|
|
1063
|
+
### Sizing
|
|
1064
|
+
`.full-width` — `inline-size: 100%`. Stretch an element to fill its container's inline size. Useful on elements that don't fill by default (such as `<table>`, `<figure>`, inline-block elements, flex/grid children).
|
|
1065
|
+
|
|
1066
|
+
`.full-height` — `block-size: 100dvh`. Fill the dynamic viewport height. Useful for hero/splash sections and full-screen drawers. On an `<aside>`, it opts into the full-height side-menu pattern: the aside becomes a flex column, a child `<nav>` can scroll, and a child `<footer>` stays at the bottom (see Side menu).
|
|
1067
|
+
|
|
1068
|
+
### Overflow
|
|
1069
|
+
`.overflow-x` and `.overflow-y` — scroll a container on one axis when its content overflows. Most often used to wrap a wide `<table>` so it scrolls horizontally without changing the table's `display: table` layout.
|
|
1070
|
+
|
|
1071
|
+
### When to reach for a project class instead
|
|
1072
|
+
If you stack several utilities on the same element, that element wants to be a project class. Utilities are for the one-off; recurring patterns belong in your `@layer project` CSS, named for their intent.
|