Using components
A push that carries a format 0.3 component writes two kinds of file you can use
in a page as they are: components.css, the CSS for every 0.3 component, and
one HTML snippet per component. This page says how to load them and what to
expect from them.
What you get
| File | What it is |
|---|---|
tokens/tokens.css |
Your tokens as CSS custom properties, one block per mode. |
tokens/components.css |
Every 0.3 component's CSS. It names your tokens with var() and nothing else. |
tokens/components/<name>.html |
The component's markup, and one example per variant. |
tokens is your project's token folder. All three files are generated and
overwritten by every push. Edit the project in Kampa, or the component
documents, never these files.
Because components.css holds only var() references, it is the same for
every mode: switching data-theme switches the variables, and the components
follow. A token change in Kampa never needs new component CSS.
Loading them
Load tokens.css, then components.css, before your framework's CSS:
<link rel="stylesheet" href="/tokens/tokens.css">
<link rel="stylesheet" href="/tokens/components.css">
<link rel="stylesheet" href="/your-app.css">
components.css starts with @layer kampa.base, kampa.components; and puts
every rule in the kampa.components layer. Two things follow:
- Your own unlayered CSS always wins over Kampa's, whatever its order or specificity. A single class of yours overrides a Kampa rule.
- Layers are ordered by first appearance. Loaded first,
kampais the lowest layer, and a framework's layers (Tailwind'stheme,base,components,utilities) sit above it. Loaded after a framework, Kampa's rules would beat that framework's utilities. Kampa cannot see your import order, so this is the one rule to keep.
To place Kampa against your own layers, name kampa: @layer kampa, mine;
puts yours above it, @layer mine, kampa; below.
Every rule is wrapped in :where(), so it has no specificity of its own
(pseudo-element rules, such as a checkbox's check, have the specificity of one
element). Order decides between Kampa's own rules, the same order the Kampa
check grades.
Markup
Copy the element from the snippet. Each component is one element with one
class, kampa-<component>, plus one class per variant that is not the
default:
<button type="button" class="kampa-button kampa-button--secondary">Save</button>
<label><input type="checkbox" class="kampa-checkbox" checked> Remember me</label>
<label><input type="checkbox" role="switch" class="kampa-switch"> Notifications</label>
<input type="text" class="kampa-input" aria-label="Email" aria-invalid="true">
States are never classes. The browser shows them from the element itself:
| State | How the element gets it |
|---|---|
| hover, active, focus-visible | The pointer and the keyboard. |
| checked | The checked attribute, or the user. |
| disabled | The disabled attribute. A link has none: remove its href and set role="link" and aria-disabled="true". |
| invalid | aria-invalid="true", which you set when the value is wrong. Kampa does not style :invalid, so an empty required field is not shown as an error before anyone touches it, and an error is never only visual. |
| open | The browser, when a select is open. |
No JavaScript is needed for any of them.
The snippets give every form control a name, with a <label> or
aria-label. Keep one when you change the markup: the snippet's text is a
sample, the name is not optional.
Focus
Kampa's CSS removes the browser's default focus outline and draws the ring the component declares, outside the control with a gap. Every focusable component declares one, and the check grades it at 3:1 against your general surfaces. If you restyle a component, keep a visible ring.
Forced colours
Under Windows High Contrast and other forced-colours modes the browser
replaces colours with the user's own. components.css carries a small block
for that mode that redraws the checkbox check, the radio dot and the switch
thumb with system colours, so checked and unchecked still look different.
Those colours are the user's and are not graded.
The starters
A new project starts with eleven components in format 0.3, each with every state its native element has:
| Component | Element | Variants | Sizes |
|---|---|---|---|
| Button | button |
primary, secondary, ghost, destructive | sm, md, lg |
| Link | a |
default, subtle | |
| Badge | span |
info, success, warning, error | |
| Input | input type="text" |
sm, md, lg | |
| Textarea | textarea |
sm, md, lg | |
| Select | select |
sm, md, lg | |
| Checkbox | input type="checkbox" |
||
| Radio | input type="radio" |
||
| Switch | input type="checkbox" role="switch" |
||
| Separator | hr |
||
| Avatar | span |
sm, md, lg |
A size is a class like a variant, kampa-button--lg; md is the default and
has none. Card and Alert are still format 0.2: they have no snippet and are not
in components.css.
They name these tokens, which every template and the generator add:
| Token | What it is |
|---|---|
size.control.xs to size.control.lg |
Control heights: 20, 32, 40 and 48px. A project generated at the compact density gets 16, 28, 32 and 40px. |
opacity.disabled |
0.5. A disabled control is shown at this opacity. |
color.border.focus |
The ring: your brand colour, or the next step along its ramp that reaches 3:1 on every general surface, or your text colour. |
borderWidth.medium |
The ring's width and its gap from the control: 2px in every template and every generated project. |
A few choices follow from what the check grades:
- A control's edge identifies it, so it is graded at 3:1 on the page in every
state. The starters use
color.foreground.mutedfor it. - A link's text is graded on the page as text, at 4.5:1. The starters use
color.brand.emphasisfor it. - A link paints
color.background.defaultbehind its text: format 0.3 grades the text of every component on its own background. - Destructive buttons keep their colours on hover and press, because no token means "error, hovered". The pointer and the ring still change.
A project made before format 0.3 has Button, Input, Checkbox and Badge in
format 0.2. In Kampa, Update replaces them with the 0.3 starters and adds the
size.control, opacity.disabled and color.border.focus tokens the project
does not have. It never changes a token you already have, borderWidth.medium
included. A starter you customised is replaced too, and Kampa asks first.
After your next push, the repository has components.css and the snippets.
Starter markup
Each starter's snippet, as generated. A push writes the same markup, with one
example per variant, to tokens/components/<name>.html.
<!-- Avatar -->
<span class="kampa-avatar">AB</span>
<!-- Badge -->
<span class="kampa-badge">Badge</span>
<!-- Button -->
<button type="button" class="kampa-button">Button</button>
<!-- Checkbox -->
<label><input type="checkbox" class="kampa-checkbox"> Checkbox</label>
<!-- Input -->
<input type="text" class="kampa-input" aria-label="Input" placeholder="Placeholder">
<!-- Link -->
<a class="kampa-link" href="#">Link</a>
<!-- Radio -->
<label><input type="radio" class="kampa-radio"> Radio</label>
<!-- Select -->
<select class="kampa-select" aria-label="Select"><option>Option 1</option><option>Option 2</option></select>
<!-- Separator -->
<hr class="kampa-separator">
<!-- Switch -->
<label><input type="checkbox" role="switch" class="kampa-switch"> Switch</label>
<!-- Textarea -->
<textarea class="kampa-textarea" aria-label="Textarea" placeholder="Placeholder"></textarea>
The text inside and the placeholder are samples. Replace them, and keep a name on every form control.
A select draws its chevron in its inline-end padding, so components.css keeps
28px there whatever padding-inline a size declares. The text never runs
under the chevron.
What is not graded
- The open list of a
selectis drawn by the browser. The closed control is graded; the list is not. - Surfaces other than your general ones. A border or a focus ring is
graded against
color.backgroundandcolor.surface(default,subtle,muted). A component placed on a brand, inverted or card surface is not graded against it. - Your own overrides. A rule of yours that changes a colour is not something the Kampa check can see.