Element Patterns

Native-first action, form, identity, navigation, feed, and application primitives.

These patterns fill the gaps identified in the Graffiti UI comparison. They ship through index.css, use semantic state as their contract, and work without JavaScript unless an enhancement is explicitly described.

Icon buttons and switches

Use a real labelled button for icon-only actions. A switch is a native checkbox whose role="switch" provides the visual contract.

Compact native controls

<button class="icon-button" aria-label="Close">×</button>
<label>
<span>Automatic updates</span>
<input type="checkbox" role="switch" checked>
</label>

[data-icon-button] is equivalent to .icon-button. <icon-button> is only a visual host and does not gain native button behavior, keyboard support, or form semantics automatically. Floating actions use .fab or [data-fab], include safe-area-aware logical offsets, and should represent the page’s primary action. Text symbols and explicit svg, img, or [data-icon] children share the same centered square. Icon controls intentionally use --text-box-icon instead of label-oriented cap/alphabetic trimming.

Connected fields that adapt

https://.css-tags.devUse a short, memorable project name.
<layout-stack container-query>
<input-group data-stack="auto">
<span class="input-affix">https://</span>
<input class="form-input" aria-label="Project name">
<button class="form-button">Create</button>
</input-group>
<search-input>
<svg data-search-icon aria-hidden="true"><!-- search icon --></svg>
<input type="search" aria-label="Search projects">
<kbd aria-hidden="true">⌘ K</kbd>
</search-input>
</layout-stack>

Input groups connect adjacent controls. Search input provides leading and trailing content slots around a native input type="search". With data-stack="auto", a group stacks at narrow viewport widths or inside an opted-in layout-container, as the resizable preview demonstrates.

File dropzone

Native file input drop target

Drop files here or choose filesPNG, JPG, or WebP up to 10 MB

The transparent native file input covers the surface, preserving click, keyboard, and browser drop behavior. JavaScript may set data-dragover="true" and render selected filenames, but neither is required for the control to work.

Rating and reactions

Read-only and interactive ratings

★★★★★
Rate this example

Interactive ratings use native radios. Put labels in descending value order, as shown. Reactions remain an ordinary select and use customizable select only where appearance: base-select is supported.

Avatars

Initial, image, and group avatars

ALGHALGHKJ

An img child fills the avatar when present; text initials remain the fallback. Size values are sm, the default, and lg. Use shape="square" when needed.

Toolbar and navigation

Editor toolbar and rich navigation

Use variant="flush", data-variant="flush", or .is-flush for a quieter sidebar or table of contents. It removes boxed rows while retaining hover, focus, and an aria-current="page" indicator.

<ul data-list-navigation data-variant="flush">
<li><a href="/overview" aria-current="page">Overview</a></li>
<li><a href="/settings">Settings</a></li>
</ul>

Use role="toolbar" for a related control group. List navigation expects real links or buttons and uses aria-current="page" for selection. icon-rail, [data-icon-rail], and .icon-rail provide the compact vertical equivalent; every icon-only destination still needs an accessible name.

Messages and logs

Application feedback surfaces

Can you review this deploy?Yes. The checks are passing now.
Production deployPassed
Dependencies installed
Site built
Publishing assets

aria-busy="true" adds a visual thinking indicator to a bubble. It does not announce updates by itself. Use role="log" and an appropriate live-region strategy only when rows are appended dynamically.

Vertical snap feed

snap-feed, [data-snap-feed], and .snap-feed provide a vertical scroll-snap container. Its direct children snap to the block-start edge. This is separate from the existing horizontal layout-reel and from carousel.

<snap-feed aria-label="Updates">
<article>First full-height item</article>
<article>Second full-height item</article>
</snap-feed>

Set --snap-feed-height, --snap-feed-item-min-height, and --snap-feed-strictness to adapt the viewport. Avoid mandatory snapping for items taller than the feed viewport.

Public host forms

Surface and layout patterns support custom, data-*, and class hosts. Native interaction remains canonical:

  • input-group, [data-input-group], .input-group
  • search-input, [data-search-input], .search-input
  • file-dropzone, [data-file-dropzone], .file-dropzone
  • rating-output, [data-rating-output], .rating-output
  • rating-input, [data-rating-input], .rating-input
  • reaction-select, [data-reaction-select], .reaction-select
  • user-avatar, [data-avatar], .avatar
  • tool-bar, [data-toolbar], .toolbar
  • nav-list, [data-list-navigation], .list-navigation
  • icon-rail, [data-icon-rail], .icon-rail
  • message-bubble, [data-bubble], .bubble
  • log-card, [data-log-card], .log-card
  • snap-feed, [data-snap-feed], .snap-feed