Skip to content

Guides

Authoring standard

Write standard HTML. Choose each element for its meaning and native behavior, then opt into Thin-Sky with a thin-* class, a documented data-* option, or a documented --thin-* property. Add a div or span only when a layout needs a box and no element means more.

HTML element reference · Accessibility contracts

Kinds of item

foundation (14)
Document-wide defaults and tokens: the reset, element defaults, themes, type and space scales, icons, and motion.
layout (16)
CSS that arranges the child boxes of an authored element. layouts.css is generated from their style specs.
component (41)
A reusable presentation contract for one or more native elements, with an optional behavior when the interaction needs it.
pattern (58)
A composition of layouts, components, and native elements for a recurring page section or task.
recipe (37)
A complete interaction or workflow that can use patterns, components, and server responses.

Choosing a hook

Baseline presentation: Element selectors in /foundation.css

Low-specificity element rules give text, links, focus, and media readable defaults. The browser supplies the rest of each element's behavior.

<p>Readable without a class.</p>

Opt-in layout, skin, or pattern: class="thin-<item>"

Apply the item's class to the semantic element, or to a neutral div or span when the item has no inherent semantics. Parts are selected by tag when their role is unambiguous and get their own class otherwise.

<ul class="thin-stack">…</ul>

Named presentation option: data-space, data-variant, data-size, data-tone

One short attribute per independent option, on the element with the class, so options combine. Each item documents its values and default. A variant or tone changes appearance, never meaning.

<button class="thin-button" data-variant="quiet">Save</button>

Exact value or theme override: --thin-* custom properties

Set a documented public property in consumer CSS or a style attribute; a property takes precedence over the matching attribute preset. Private --_thin-* properties are internal.

<ul class="thin-stack" style="--thin-stack-space: 1.25rem">…</ul>

State the browser already knows: Native attributes, pseudo-classes, and truthful ARIA state

Style :disabled, :checked, [open], :user-invalid, or [aria-current="page"] rather than a parallel state class. Errors come from the real validation state with associated text.

<a href="/" aria-current="page">Home</a>

Optional behavior: data-enhance="<behavior>"

Attach a behavior to the existing native host. It initializes, refreshes after a morph, and disposes; presentation classes and application state stay independent of it.

<div class="thin-tabs" data-enhance="tabs">…</div>

Theme scope: data-theme="<theme>"

Selects a complete theme for the element and its descendants.

<section data-theme="night-signal">…</section>

Configuring a component

Use an existing HTML attribute when one fits: type for a button's action, disabled for an unavailable control, open for an expanded disclosure. Otherwise add one data-* attribute per independent option, and use a custom property for a value that needs no named preset.

Stack's named spacing steps are 2xs, xs, s, l, xl, each mapped to a theme token. Where typed attr() is supported, data-space may also hold a literal length; set --thin-stack-space to require an exact gap in every browser.

Component styles follow Piccalilli's configurable button approach: private --_thin-* configuration at the start of the rule, consumed by the declarations, and reassigned by presets scoped to the component.

Example: a disclosure

.shipping-faq is an application class. Stack spaces the answer, and the browser updates open as the reader toggles it, so CSS reads both without a script.

<details class="shipping-faq">
  <summary>How do I track an order?</summary>
  <ol class="thin-stack" data-space="s">
    <li>Open your shipping confirmation.</li>
    <li>Follow the tracking link.</li>
  </ol>
</details>
:where(details.shipping-faq[open] > summary) {
  font-weight: 700;
  margin-block-end: var(--thin-space-s);
}

Interaction and accessibility

Use native state as the styling source

Preserve hidden, hidden="until-found", and inert. Let the browser own :popover-open, modal state, top-layer placement, and native focus. An overlay keeps a usable inline or full-page destination when enhancement is absent. MDN: Popover API

Style the right interaction state

Keep a visible :focus-visible indicator, use :focus-within for a surrounding group, and make hover cues available to keyboard and touch. Use aria-pressed and aria-expanded only for the matching behavior; aria-disabled also needs behavior that prevents activation.

Keep interaction on native hosts

Behaviors attach to standard elements and keep their authored content. Each item's accessibility contract names the native mapping or the one APG pattern it applies, and a useful link, form, or visible-content fallback remains. Accessibility contracts

Treat anchor positioning as presentation

A popover trigger stays a native button with popovertarget, the popover holds ordinary links and forms, and a durable destination remains. The browser owns collision handling, light dismiss, Escape, and focus return; no script reads geometry.

Design for user settings and difficult content

Use logical properties, respect writing direction and text size, and keep focus visible at zoom and narrow widths. Check long labels, forced colors, reduced motion, print, and non-colour cues, and keep source order and keyboard order aligned.

Prove the fallback

Gate new CSS capabilities with @supports. Check the native HTML without CSS, the styled page without JavaScript, and the enhanced path in the browser lanes. Platform experiments

Cascade layers

Every Thin-Sky stylesheet starts by declaring the same layer order, so the first one loaded fixes it. Override library rules with unlayered CSS, or with an application layer declared after these.

  1. thin-reset: Box sizing and the browser-default corrections every page needs.
  2. thin-themes: Theme tokens: colour roles, type and space scales, and forced-colors mappings.
  3. thin-foundation: Low-specificity element defaults for text, links, focus, media, and forms.
  4. thin-layouts: Layouts that arrange child boxes on an authored element.
  5. thin-components: Component skins for native elements and their variants.
  6. thin-patterns: Compositions for recurring page sections and tasks.
  7. thin-utilities: Reserved for single-purpose overrides; the library ships none.

Source and distribution

Item styles are authored as style specs and generated into the shipped stylesheets with bun run css:generate. The public CSS contract is the system tokens plus the custom properties each item documents, recorded in the package's API snapshot. Applications load the generated assets from the CDN.