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.
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.
thin-reset: Box sizing and the browser-default corrections every page needs.thin-themes: Theme tokens: colour roles, type and space scales, and forced-colors mappings.thin-foundation: Low-specificity element defaults for text, links, focus, media, and forms.thin-layouts: Layouts that arrange child boxes on an authored element.thin-components: Component skins for native elements and their variants.thin-patterns: Compositions for recurring page sections and tasks.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.