Use semantic HTML first. Add ARIA only when native semantics are not enough.
- Page container:
.elum-containeron<main>(or any block element) — centers content, applies--elum-container-widthmax width, and pads with--elum-container-padding-inline/--elum-container-padding-block. Override the tokens to reframe the page. - Vertical rhythm:
.elum-stackon a container adds a top margin (--elum-space-3) to every child after the first. Compose with.elum-containerfor a complete page skeleton:<main class="elum-container elum-stack">.
- Class:
.elum-buttonon a native<button> - Variants: the default
.elum-buttonis the secondary style (bordered, no fill). Adddata-variant="primary"for a filled accent button ordata-variant="tertiary"for a borderless button. - Disabled: native
disabled - Keyboard: native button activation (Enter / Space)
- Wrapper:
.elum-fieldaround the control, with a connected<label for="..."> - Prompt input: wrap
.elum-inputin.elum-prompt-fieldand place.elum-input-promptbefore it for a persistent prompt such as> - Invalid state:
aria-invalid="true" - Disabled state: native
disabled - Keyboard: native form element behavior
- Note: the
<select>dropdown pop-up on Linux running Chromium is rendered as a native GTK window and follows the system GTK theme regardless ofcolor-scheme. On dark themes, the popup will appear light if the system GTK theme is light. This is a platform boundary. Switch to a dark system GTK theme for full consistency.
- Wrapper:
.elum-choicelabel for larger click targets - Radio groups: wrap in
<fieldset>with<legend> - Disabled: native
disabledon the input; optionaldata-disabled="true"on.elum-choicefor the visual hint
- Plain card:
<article class="elum-card"> - Labeled card (title in border):
<article class="elum-card elum-card-labeled"> - Header region:
<header class="elum-card-header">with.elum-card-titleand optional.elum-card-subtitle - Subtitle defaults to card body flow, below the border label.
- Inline subtitle (beside the title):
<header class="elum-card-header" data-inline="true">— only for short subtitles
- Class:
.elum-alert - Tones:
data-tone="success" | "warn" | "error" - Live region: prefer
role="status"and/oraria-live="polite"for status messaging - Default themes use a compact palette, so some tones may share a color. Edit theme tokens after copying ElumKit source when your application needs stronger visual distinction.
- Class:
.elum-badge - Tones:
data-tone="accent" | "success" | "warn" | "error" - Use for compact bracketed status text such as
[WARNING]. - Default themes use a compact palette, so some tones may share a color.
- Class:
.elum-status-label - Tones:
data-tone="accent" | "success" | "warn" | "error" - Use for compact inline status text in dense rows and tables.
- Status labels render with a same-color dot and short uppercase status text such as
READYorREVIEW. - Default themes use a compact palette, so some tones may share a color.
- Class:
.elum-system-bar - Brand label:
.elum-system-bar-brandfor the primary label - Compact key/value items: group with
.elum-system-bar-group - Status values may use bracketed status text for terse terminal-style state.
- Keep system bar copy short enough to wrap cleanly on narrow screens.
- Wrapper:
.elum-navbaron a<nav>; sticks to the top of the viewport - Brand:
.elum-navbar-brandon the wordmark label - Links:
.elum-navlinkscontaining.elum-navlinkanchors - Current page:
aria-current="page"on the active link - Use for top-level page navigation. For switching views on one page, use tabs.
- Tablist:
.elum-tabswithrole="tablist"and an accessible name - Tab:
.elum-tabon a<button role="tab">witharia-selected, anid, andaria-controlsfor its panel - Panel:
role="tabpanel"witharia-labelledby; hide inactive panels withhidden - Roving focus: active tab
tabindex="0", otherstabindex="-1" - Switches between views on one page. Requires JavaScript for panel switching and keyboard support; see
examples/playground.html. For page navigation, use the navbar.
- Wrapper:
.elum-toolbar; addrole="group"and an accessible name when the controls need an announced group - Groups:
.elum-toolbar-groupfor related actions or metadata - End alignment:
data-align="end"on a toolbar group - Metadata:
.elum-toolbar-labeland.elum-toolbar-value - Use for page actions, refresh controls, status labels, and compact metadata. Keep behavior in application code.
- Wrapper:
.elum-queryon a<form> - Search landmark: add
role="search"and an accessible name such asaria-label="Service filters"when the form filters page or table content - Compose with existing
.elum-field,.elum-input,.elum-select, and.elum-buttonclasses. - Keep filtering behavior in application code.
- Wrapper:
.elum-paginationon a<nav aria-label="Pagination"> - Status text:
.elum-pagination-statusfor compact page range or count text - Use real links for navigable pages and buttons for client-side page changes.
- Disable unavailable controls with native
disabledwhen using buttons.
- Wrapper:
.elum-emptyfor a compact no-content message - Title:
.elum-empty-titlefor the short state label - Message:
.elum-empty-messagefor supporting detail - Use inside cards, table cells, or list regions when there is no content to show.
- Place table empty states inside a
<td colspan="...">so table structure stays valid. - Add live-region semantics only when an application updates the empty state dynamically and users need the change announced.
- Wrapper:
<details class="elum-disclosure"> - Summary:
<summary class="elum-disclosure-summary"> - Content:
.elum-disclosure-contentfor the expanded body - Use native
<details>and<summary>so disclosure behavior works without JavaScript. - Keep summary text specific enough to identify the content being expanded.
- List:
<dl class="elum-detail-list"> - Row:
.elum-detailaround each term/value pair - Term:
.elum-detail-termon<dt> - Value:
.elum-detail-valueon<dd> - Use for stable facts such as identifiers, timestamps, statuses, and configuration values.
- Use real
<dt>and<dd>elements so assistive technologies receive definition-list semantics.
- List:
.elum-metrics - Row:
.elum-metric - Use
.elum-metric-label,.elum-metric-value, and.elum-metric-unitfor aligned telemetry.
- Wrapper:
.elum-meteron a<div> - Track:
.elum-meter-trackon a<div>withrole="meter",aria-valuenow,aria-valuemin, andaria-valuemaxfor correct AT announcements - Fill width:
style="--elum-meter-fill-width: N%"on the track element, matching the value as a percentage of the range - Fill tones:
data-tone="success" | "warn" | "error"on the track element - Label:
aria-labelon the track element, oraria-labelledbypointing to a visible.elum-meter-label - Why not
<meter>: styling<meter>internals requires deprecated non-standard pseudo-elements (::-webkit-meter-baretc.) that MDN recommends against.<div role="meter">provides equivalent accessibility with full CSS control.
- List:
.elum-list - Row:
.elum-row - Use
.elum-row-title,.elum-row-meta, and.elum-row-valuefor compact aligned content. - Selected state:
data-selected="true"for the visual hook, plus the appropriate semantic state for the context. For a current link, usearia-current="true".
- Wrapper:
.elum-table-wrap - Table:
.elum-table - Responsive narrow rows:
data-labelon each cell - Numeric columns:
data-numeric="true"anddata-align="end" - Status column:
data-column="status"on header and cells to keep status output aligned