Lit web components
Reusable components, documented and ready to explore.
A collection of universally usable web components for various tasks.
Install
npm install @f-ewald/components
Import the whole library, or use a component subpath so applications only load what they use.
import "@f-ewald/components";
import "@f-ewald/components/confirm-dialog.js";
99 components
Component reference
-
<action-bar>Toolbar that sits directly above a list or table: a left cluster for search and filters and a right cluster for record actions (create, delete, bulk actions). It's a presentational layout container only — drop any controls (autocomplete-input, multi-select, ui-button, …) into the start and end slots; the bar owns none of their behavior and adds no search field of its own. The two clusters wrap onto separate rows when the bar is too narrow. -
<address-autocomplete>Form-associated text input with a suggestion dropdown. Works as a drop-in replacement for a plain <input name="address">: consumers keep reading new FormData(form).get("address") and calling form.reset() unchanged. -
<animate-confetti>Fullscreen confetti animation overlay, rendered on a fixed-position canvas. Starts automatically on first render and stops after duration ms. -
<app-shell>The dashboard page shell: a slot-based CSS-grid backbone that arranges a top bar, the main content, an optional right-hand detail column, an optional footer, and a sidebar. The top bar always spans the shell's full width, in every sidebar state. -
<app-sidebar>Collapsible navigation sidebar for the app-shell sidebar slot. It is deliberately presentational and router-agnostic: the consumer supplies the nav items as plain <a>/<button> elements (each an icon followed by a label), optional <p> group headings, and marks the active item with aria-current="page". The sidebar styles them, tracks hover/active/focus, and — in collapsed "rail" mode — centers the icons and hides the labels. -
<audio-player>Compact audio player wrapping a native <audio> element (kept off-screen for its decoding/playback engine and free timeupdate/loadedmetadata events) behind a tokenized transport bar: a play/pause icon-button, elapsed/total time, a seekable progress bar, and a mute toggle + volume slider. The seek/volume sliders are native <input type="range"> elements (see utils/transport-controls.ts) for free keyboard and pointer support, per this package's "native semantics before custom ARIA" rule. -
<auto-scroll>Wraps arbitrary slotted content (e.g. timeline-container) and keeps it scrolled to the bottom as new children are appended — but only while the user is already scrolled near the bottom ("stick to bottom", a chat/log- viewer convention). If the user has scrolled up to read earlier content, new content does not yank the scroll position back down. -
<autocomplete-input>Generic form-associated text input with a suggestion dropdown, for any "type to filter a list of {key, value} options" use case. Works as a drop-in replacement for a plain <input> inside a <form>: set name on the element itself and consumers keep reading new FormData(form).get(name) and calling form.reset() unchanged — the submitted value is the picked option's value, while key is available via the option-select event and the selectedOption getter for cases that need the underlying id rather than the display text. -
<blink-cursor>A small inline blinking cursor glyph for terminal- or editor-styled headings, prompts, and status lines. It renders its own decorative character so consumers can append it directly to adjacent text while inheriting the surrounding typography. -
<breadcrumb-nav>A breadcrumb trail: a <nav aria-label="Breadcrumb"> wrapping an ordered list, with chevron separators and the current page rendered as plain, non-interactive text. Designed to drop into page-header's breadcrumb slot, but usable on its own anywhere a trail is needed. -
<button-group>Single-select segmented control — a strip of buttons joined into one shared-border shape, for a small, persistent set of mutually exclusive choices (a view switcher, a theme picker) where the currently selected option should read as visually "pressed," not just checked. For many short, individually pill-shaped choices, use radio-pills instead. Wraps native radio inputs for keyboard/a11y and fires change rather than relying on form submission. Set size="sm" for a compact strip one step below the default, matching ui-button's sm size. -
<calendar-day>A single day rendered as an hourly time grid — a Google-Calendar-style view distinct from calendar-month's whole-day table. Declarative calendar-entry children with a time-of-day in start/end (e.g. start="2026-03-05T09:00") render as positioned/sized blocks; entries with only a date (no time) render in an all-day band above the grid. Overlapping timed entries stack into side-by-side columns; overlapping all-day/multi-day entries stack into lanes, same as calendar-month. Read-only. -
<calendar-entry>Declarative metadata for one calendar event, consumed by a parent calendar-month or calendar-year. Read-only/non-interactive; renders nothing itself. -
<calendar-month>One month rendered as a top-to-bottom list of days — weekends and today highlighted, with declarative calendar-entry children shown as colored bars spanning the days they cover. An entry's title uses its first visible day; every remaining visible day becomes one shared body for wrapped details and an optional ending footer. Overlapping entries stack into side-by-side lanes rather than being layered/hidden. Read-only. -
<calendar-week>Sunday-through-Saturday week rendered as one shared hourly time grid — the seven-day sibling of calendar-day. Unlike calendar-year composing 12 calendar-month children, this is its own independent 7-column layout (not 7 nested <calendar-day> elements): a single hour gutter is drawn once, and multi-day/all-day entries span the days they cover as one continuous bar in a shared all-day band, since lanes for that band are assigned once across the whole visible week (unlike calendar-month's documented per-instance lane limitation). Timed entries stack into side-by-side columns independently per day, same as calendar-day. Read-only. -
<calendar-year>A full year of calendar-month blocks, generated from declarative calendar-entry children. Each entry is re-projected into the calendar-month blocks it overlaps as a freshly-created calendar-entry element — the original elements stay slotted here and are never moved, since a DOM node can only have one parent. Read-only. -
<card-grid>A responsive auto-filling grid shell for link-card (or any card-shaped content) — each slotted child becomes a grid item, wrapping to a new row once the container is too narrow for another 15rem column. -
<chat-message>One conversation entry in a chat-style activity feed. Tool calls and "thinking" traces are variants of this component rather than separate ones — they share the same header, collapse behavior, and body card as a normal message, just dimmed and collapsible with an always-visible summary. -
<chevron-panel>A generic disclosure: a clickable header that expands/collapses a body, with a chevron that rotates to reflect state. Headline and body are both slotted, so any markup can go in either — unlike chat-message's built-in collapsible mode, which only slots the body and builds its header from discrete properties (author/timestamp/summary). -
<code-diff>A compact, read-only code diff viewer: a bordered panel with a header bar for filename and stat, followed by a numbered <pre> listing of lines. Each CodeDiffLine renders as "add", "del", or "context" with fixed "+ " / "- " / " " prefixes so the diff remains understandable even when color is unavailable. -
<comment-composer>GitHub/Slack-style comment composer: a one-line text field that expands into a multi-line textarea with a bottom-right Cancel/Submit footer (form-actions) as soon as it's focused or clicked. Submitting fires submit with the trimmed value, then clears the field and collapses back to one line — it's meant for posting one comment at a time, not editing a persistent value in place (see editable-text for that). Canceling (the Cancel button or Escape) discards the draft and collapses without firing submit. Clicking away (blur) does neither — the composer stays expanded until the user explicitly submits or cancels. Cmd/Ctrl+Enter submits from the textarea, matching editable-text's multiline shortcut — the Submit button always shows a kbd-hint for it, so the shortcut is discoverable rather than a hidden power-user feature. Calling the standard .focus() method expands the composer (if collapsed) and focuses its field, for an ancestor that wants to drive it programmatically. Purely token-styled (no bespoke colors), so it's themeable via the same --ui- custom properties as every other value-entry field. -
<comment-label>A code-comment-style eyebrow line for section chrome in terminal- or editor-themed pages. It renders a colored comment marker (## by default) before muted slotted text, so <comment-label>the_whole_idea</comment-label> reads like a short section kicker. Set prefix="//" and italic for a closing or footer quote line that keeps the marker upright while the message itself turns italic. -
<confirm-dialog>Reusable confirmation dialog: overlay + centered card with a slotted body, an optional error line, and Cancel/Confirm actions. Instant display:none → display:flex toggle (no transitions). Fires confirm/cancel (bubbling, composed) instead of owning any deletion logic itself — callers stay in charge of the request. Set size="sm" for compact actions one step below the default, matching ui-button's sm size. -
<content-divider>A horizontal divider: a thin rule that visually separates two pieces of content that are not otherwise contained in a box or frame and would bleed into each other. With a label it renders the common "─── OR ───" pattern — text centered between two line segments; without one it is a single full-width rule. Exposed to assistive technology as a horizontal separator, so it renders correctly with zero external CSS. -
<copy-link-button>Small icon button that copies value to the clipboard and shows a toast on success/failure (if a <toast-notification> element is present), and always dispatches a copy-success/copy-error CustomEvent so consumers without a toast element can react. Defaults to the current page URL if value is unset. -
<countdown-timer>Per-second ticking count-down timer, e.g. a live "Retrying in 3 seconds" indicator while waiting to retry a failed request. Renders nothing while until is unset or unparseable. Remaining time is clamped to zero — it never goes negative once the target instant has passed. -
<cron-schedule>Repeat-schedule picker that reads and writes a standard 5-field cron expression. The collapsed trigger shows a compact English description of the current schedule ("Every hour", "10:17 every Monday"); clicking it opens an anchored panel with the schedule form. -
<data-table>A generic, presentational table shell: renders a <thead> from columns and one <tr> per entry in rows, with each cell's content produced by renderCell (default: plain property lookup on the row object). Knows nothing about what a "row" means — callers own the data shape entirely. -
<distance-value>Inline distance display. Renders miles/feet or km/m, switching units at sensible thresholds (< 0.25 mi → ft; < 0.5 km → m). -
<distribution-chart>Renders a KDE distribution curve for a named metric with one or more value markers. The SVG viewBox is kept in sync with the element's pixel width via ResizeObserver so that font sizes and stroke widths are always in real pixels regardless of container width. -
<dropdown-button>A button that opens an anchored menu of actions — essentially form-select minus "current value" semantics: a menu, not a select. Use for a set of mutually exclusive next-step actions (e.g. a failed task's Retry / Close / Backlog, or a table row's overflow actions). -
<editable-text>Jira/GitHub-style click-to-edit text: a display span that turns into an <input> (or auto-growing <textarea> when multiline) on click. The input/textarea inherits the host's font, so a title wrapped in an <h1> edits at title size. -
<empty-state>A centered placeholder for an empty list, an empty panel, or a zero-result search: an optional leading glyph, a heading, a supporting line (or richer slotted body), and an optional call-to-action row. Purely presentational — it carries no interactive state of its own and no ARIA role; it is a region of content, not a live status. Every optional part collapses completely when absent, reserving no layout space. -
<form-actions>Form footer button bar with a fixed action order for internal apps: the primary (submit) button is always rightmost, the secondary (cancel) button sits to its immediate left, and an optional tertiary/destructive action is pinned to the far left. The order is enforced by the component regardless of the source order the buttons are authored in, so every form in a product reads the same way. -
<form-field>Per-field wrapper for a form control: label, slotted control, and an optional hint or error message, in one consistent unit repeated across a form. Purely presentational — composes whatever control is slotted (form-select, multi-select, autocomplete-input, ui-checkbox, etc.) without intercepting its events or value. -
<form-select>A styled dropdown select: a trigger button showing the current option's label, opening a listbox popover on click. Drop-in generic replacement for a native <select> wherever consistent cross-browser styling and a change event carrying { value } are wanted (e.g. a task's status picker). -
<frame-box>A titled frame around a slot: a gray border with a small uppercase, muted label overlapping the top edge (fieldset/legend-style). Generic — the label text is entirely up to the consumer (e.g. "Debug" to visually fence off dev-only chrome from the product UI). -
<fullscreen-button>Toggles fullscreen presentation of the page, or of a given target element. -
<gallery-item>Declarative image metadata consumed by a parent photo-gallery. -
<gallery-item-variant>Responsive image source metadata for a parent gallery-item. -
<icon-button>A borderless button wrapping a passed-in icon, with a rounded hover-highlight background. Use for a low-emphasis affordance next to content it acts on (e.g. an "Edit" pencil at the end of a table row) where a bordered ui-button would be too heavy. -
<kanban-board>A configurable kanban board: a horizontally scrolling row of columns, each holding cards. A card's column is its state — moving a card to another column (by drag-and-drop, keyboard, or the detail popover's state selector) changes its state, and the board emits a single card-move for all three. -
<kanban-card>A single kanban card's compact overview: its ticket number and title only. Purely presentational and metadata-only — it is created and driven by kanban-board, which owns drag-and-drop, selection, and the richer detail view (description, state, and timestamps live in the board's popover, not here). The board sets draggable, toggles the dragging/grabbed attributes for pointer and keyboard moves, and binds the open/keyboard handlers; focus is delegated to the inner control so the board can move keyboard focus to a card after a move. -
<kanban-column>A single kanban column: a titled, vertically scrollable region that holds its kanban-card children (its default <slot>), with a header showing the column title and card count. Purely presentational and metadata-only — kanban-board creates it, positions the cards inside it, and drives the drop-target highlight via the reflected dragover attribute and the empty hint via empty. -
<kbd-hint>Renders a keyboard shortcut as one boxed keycap per +-separated token. Modifier keys are platform-aware: Mod becomes Command on macOS and Control elsewhere. Keycaps derive their presentation from currentColor, so the hint works inside neutral and accent-colored controls. -
<link-card>A single linked-resource tile — logo (or an initial-letter fallback), heading, optional description, and an optional reachability status dot. Renders as a real <a> (opening in a new tab) when href is set, or a non-interactive <div> otherwise. Meant to be laid out inside card-grid, mirroring how gallery-item pairs with photo-gallery. -
<live-timer>Per-second ticking count-up timer, e.g. a live "running for 12s" or "Sleeping for 3 seconds" indicator. Renders nothing while since is unset or unparseable. -
<load-more>Click-to-load button for either end of a list. Fully property-driven: the consumer sets loading while a fetch is in flight and exhausted once there's nothing left to load; this component never fetches or manages state itself. -
<loading-dots>Three dots that bounce one after another as a lightweight, indeterminate "working" / "typing" indicator. Purely presentational and property-driven — show it while a short operation is pending and remove it when done. -
<loading-spinner>Indeterminate circular loading spinner: a rotating arc over a faint track, in the style of a browser page-load indicator. Purely presentational and property-driven — show it while work is in flight and remove it when done. -
<map-circle>A plain circular map marker: a radial-gradient fill with a soft highlight and a solid white outer ring, no point/tail (unlike <map-pin>) — for markers that don't need to visually "point" at their exact coordinate. Purely a visual primitive — it has no mapbox-gl (or any mapping library) dependency; the consumer positions it, e.g. via new mapboxgl.Marker({ element: el }). It can also replace the former <map-point> dense-layer primitive: use size="14" ring-width="3", leave the slot empty, and rasterize one marker per color for use as a map icon-image. -
<map-pin>A circular "Apple Maps"-style map pin: a radial-gradient fill with a soft highlight and a slight point at the bottom. Purely a visual primitive — it has no mapbox-gl (or any mapping library) dependency; the consumer positions it, e.g. via new mapboxgl.Marker({ element: pinEl }). -
<mapbox-map>A thin, generic wrapper around a mapboxgl.Map — construction, access token, style loading/switching, and container resizing only. It carries no domain logic: no layer registry, no click-handler system, no markers or popups. A consumer registers its own sources/layers/handlers against the mapboxgl.Map instance handed back on map-ready, the same instance mapbox-map continues to own (this component never calls map.remove() except on disconnect, so a consumer's own registrations survive style reloads exactly as they would using mapboxgl.Map directly). -
<markdown-editor>GitHub-style markdown editor: a "Write" tab holding a plain textarea and a "Preview" tab rendering the markdown body (via markdown-view). Leading YAML front matter (a ----delimited block) is detected, parsed, and shown as a key-value table above the rendered body rather than as raw text. -
<markdown-view>Renders a markdown string as sanitized, styled HTML — headings, lists, code, tables, blockquotes, and links all get token-driven styling, with wide content (code blocks, tables) scrolling in its own container instead of widening the page. -
<modal-dialog>Generic centered modal-dialog shell: overlay + card with header chrome, a close button, and an arbitrary slotted body — the modal sibling to slide-panel (fixed-edge) and popover-panel (anchored). Unlike confirm-dialog, it has no baked-in actions; the consumer supplies the body content (a form, a read-only viewer, a table) and any footer buttons itself. Instant display:none → display:flex toggle, no transition. Traps focus, closes on Escape, and restores focus to the trigger on close, stacking correctly against other open confirm-dialog/ slide-panel/popover-panel/modal-dialog layers. -
<multi-select>A form-associated multi-select: a trigger showing a compact summary of the current selection, opening a multi-selectable listbox popover, with an optional removable-chip list of the chosen values. A drop-in generic replacement for a native <select multiple> — set name on the element itself and each selected value is submitted as a repeated name=value entry, matching native multiple-select semantics; new FormData(form).getAll(name) and form.reset() work unchanged. -
<page-header>Page title block for the top of a dashboard view: an optional breadcrumb trail, the page heading with a right-aligned cluster of page-level actions beside it, and an optional description of what the page is for underneath. The actions sit in the title row rather than beside the whole block, so a longer or wrapping description never moves them. It only lays these out — the breadcrumb links and action buttons are entirely the consumer's, so it stays framework- and router-agnostic. -
<pagination-nav>Minimal, controlled pager for list/table views: a previous/next control pair around a "Page N of M" status. It owns no data — the consumer sets current-page / total-pages and moves the page in response to the page-change event (typically alongside its own data fetch), exactly like data-table leaves the row data to the caller. -
<percent-bar-chart>Bar chart for labeled rows, using D3's linear scale. Horizontal (default) renders stacked rows with bars growing rightward; orientation="vertical" renders side-by-side columns growing upward instead. mode="percent" (default) scales value against a fixed 0-100 domain and labels it with a % suffix; mode="value" scales it against max (or the largest value present) and formats it with valueFormat. -
<photo-gallery>Responsive, accessible image carousel composed from declarative gallery-item children. -
<popover-panel>Generic anchored popover shell: a floating card positioned relative to its nearest position: relative ancestor (place it next to its trigger button inside such a wrapper), as opposed to slide-panel's fixed screen-edge drawer. Closes on outside click or Escape. Header chrome and close button match slide-panel's API (heading, panel-close) so either can be swapped in for the other with no consumer-side changes beyond the wrapper. -
<price-history-chart>D3-powered SVG line chart for property price history. -
<progress-bar>A determinate horizontal progress indicator — a page-level "step 3 of 14" bar. stat-meter is the closest existing thing but is an inline CPU-gauge-style meter with a leading label and a computed percent value; progress-bar instead takes a raw value/max pair and renders an optional plain-text label to the right of the bar rather than a percent inside it. -
<radio-cards>Single-select group of full-width cards, each with a label and optional description — for a handful of meaningfully different choices where the description matters. For many short, same-shaped options (a color swatch, a basemap style), use radio-pills instead. Wraps native radio inputs for keyboard/a11y and fires change rather than relying on form submission. -
<radio-pills>Single-select group of compact pill-shaped options — for many short, same-shaped choices (a basemap style, a unit toggle). For a handful of choices where a description matters, use radio-cards instead. Wraps native radio inputs for keyboard/a11y and fires change rather than relying on form submission. -
<range-slider>A form-associated numeric range slider, usable standalone or inside a native <form>. Wraps a native <input type="range"> (kept for its free keyboard, drag, and screen-reader support) restyled to match this package's track/fill visual language (stat-meter, percent-bar-chart) instead of the browser-default appearance. Purely a value control — no built-in label; wrap in form-field for a labeled field, or render a value readout next to it (see the playground example), matching autocomplete-input/form-select. -
<relative-time>Inline relative-time display (e.g. "3 hours ago"). Accepts either a standard ISO 8601 string or a SQLite datetime('now') string ("YYYY-MM-DD HH:MM:SS", UTC, no zone marker) via datetime. Shows the full date/time in the viewer's local timezone as a hover tooltip, and re-renders on an interval so the text stays current while visible. -
<reveal-button>Button that reveals hidden slotted content when clicked. Set size="sm" for a compact button one step below the default, matching ui-button's sm size. -
<roman-numeral>Converts an integer to a roman numeral inline. -
<scroll-dots>Vertical section navigator for a long scrolled page or a slide deck: one dot per section, the active one drawn as an elongated rounded bar rather than a dot, which is the only cue needed to read position at a glance. -
<scroll-to-bottom>Overlay button that appears once the page (or a given target container) has scrolled more than threshold pixels away from the bottom edge, and scrolls back to the bottom on click. -
<scroll-to-top>Overlay button that appears once the page (or a given target container) has scrolled more than threshold pixels away from the top edge, and scrolls back to the top on click. -
<skip-link>"Skip to main content" bypass link — the package's first pure accessibility-utility component. It renders a real <a> that stays visually hidden (but in the focus order) until it receives keyboard focus, then pins itself to the top-left of the viewport as a solid, high-contrast block so a keyboard or screen-reader user can jump straight past repeated page chrome to the main content. -
<slide-panel>Generic sliding panel shell. Handles positioning, open/close animation, header chrome, and a close button. Body content is provided via the default slot; the consumer controls its own padding and overflow. -
<spec-list>A key/value specification sheet — the "spec sheet" block on a product page: a muted, wide-tracked key column against a value column, separated by hairline rules (and uppercased under themes that set --ui-label-transform). It describes ONE record's attributes, which is what sets it apart from data-table (many records, many columns, sorting); spec-list is not tabular and renders a real <dl>/<dt>/<dd> structure. -
<split-hero>Full-viewport split layout: a user-supplied photo fills one half, the default slot (typically a sign-in/sign-up form) fills the other. Below the shared 48rem breakpoint the photo becomes a blurred, full-bleed backdrop behind a solid content card instead of disappearing outright. -
<stat-meter>A compact labeled meter for a single percentage reading — e.g. CPU or memory usage in a dashboard header. percent may be null when no reading is available yet (e.g. the first tick of a polling metric); the bar then renders empty and the value shows an em dash instead of "0%". -
<stat-strip>A headless, presentational strip of headline stats — one large figure plus one muted caption per items entry, wrapping across lines on narrow viewports. Unlike stat-meter, this component does not compute percentages or render a fill bar: callers pass preformatted figure strings as-is and stat-strip only lays them out for marketing, benchmark, or dashboard summary rows. -
<status-banner>Full-width, app-level status bar for a persistent condition — "Reconnecting…", "Read-only mode", "New version available". Unlike toast-notification (which is transient, imperative, and stacks in a corner) this stays put for as long as the condition holds, so the consumer controls its presence by rendering it or not. -
<status-pill>Small colored status pill, optionally with a spinning icon — for task/run states ("Open", "Blocked", "Done") and live-activity indicators ("Running"). -
<step-ladder>A flat ordered ladder of fallback steps — an escalating "try this first, then move to the next rung only if it does not solve it" list. Each rung shows a zero-padded ordinal, a bold title, and a muted description, with a hairline rule between rows. -
<tab-bar>WAI-ARIA tabs pattern (automatic activation, roving tabindex) driving a strip of declarative tab-item children. tab-bar renders the role="tab" button strip itself, reading label/value/selected off each slotted tab-item; each tab-item owns its own visibility via its reflected selected attribute. -
<tab-item>A single labeled panel inside a tab-bar. Renders its default slot as an ARIA tabpanel, shown or hidden based on selected — tab-bar reads label/value to build its tab strip and toggles selected on the active panel. -
<terminal-block>A headless, data-driven terminal transcript shell for short install or usage instructions. Callers provide a flat ordered lines array of TerminalLine objects, and the component renders each line exactly in that order with a type-driven visual treatment: "prompt" lines get a fixed leading ❯ marker in --ui-primary, "comment" lines render as dim italic guidance, and "output" lines render as plain terminal text. -
<text-area>Plain multi-line text field — a thin, tokenized wrapper around a native <textarea>, styled to match the other value-entry form fields (autocomplete-input, form-select, ...). Not a rich editor; use readonly to display pre-formatted text (e.g. an error message) that the user can still select and copy, typically paired with <copy-link-button>. Supports form-field's opt-in floating-label mode when slotted inside it. -
<tile-grid>A generic, presentational grid shell: renders one bordered card per entry in items, with each tile's content produced by renderTile (default: stringify). Knows nothing about what an "item" means — callers own the data shape entirely. Modeled directly on data-table's headless pattern. -
<timeline-container>Vertical timeline: a connecting line runs down the entries and each slotted timeline-entry places a dot on it. This is a thin layout and semantics wrapper — the entries draw the line segments and dots themselves, so the container adds no gap between them (a gap would break the line). Exposed to assistive technology as a list of events. -
<timeline-entry>One event on a timeline-container: a dot on the vertical line, an optional headline, a relative timestamp ("3 hours ago"), and freely nested content. The connecting line is drawn here — its segment above the dot is hidden on the first entry and the segment below is hidden on the last, so the line caps exactly at the first and last dots. Only meaningful inside a timeline-container; demonstrated through it. -
<toast-notification>Fixed-position stack of dismissible notifications, anchored top-right (top-full-width on mobile). Every toast shares one fixed width so entries never appear narrower or wider than one another. Not wired to any app state yet — callers add toasts imperatively via the show() method on a live element reference, e.g. document.querySelector('toast-notification')?.show('Offline', { variant: 'error' }), or via the notifySuccess/notifyError/notifyInfo module-level helpers exported from this file. The first argument is the required bold headline; an optional description renders a smaller, non-bold second line. Each variant leads with a matching status icon (success → check, error → exclamation circle, info → information circle, warning → exclamation triangle). Each toast auto-dismisses after duration ms and can also be dismissed via its ✕ button. Appears/disappears instantly — no slide/fade transitions. -
<tree-view>A generic, presentational tree shell: renders nodes recursively, one row per node, with each row's content produced by renderNode (default: plain label). Modeled on data-table's headless pattern — knows nothing about what a node's data means beyond what renderNode does with it. -
<ui-admonition>Bordered, rounded callout card for an inline notice with an optional call to action — "take the quiz to personalize your weights", "this feature is in beta", etc. Unlike status-banner (a borderless, non-rounded full-width bar for a persistent app-level condition), this is meant to sit inline within a page's content column, so it always has a visible border and radius. Colors follow the same tinted-background + accent-color scheme as status-banner/status-pill. -
<ui-button>Button (or link styled as one) with an optional leading icon, in three visual weights. Set href to render an <a> instead of a <button> — same styling either way — for cross-page navigation that should look like an action button; a disabled/busy link stays a real <a> with aria-disabled + pointer-events: none rather than losing its href. Put the icon in the icon slot and the label in the default slot. -
<ui-checkbox>A form-associated boolean checkbox, usable standalone or inside a native <form>. Submits name=on when checked (matching native <input type="checkbox"> semantics) and participates fully in form reset(), ancestor <fieldset disabled>, and required validity. -
<user-avatar>Circular avatar. Shows src when it loads successfully; falls back to the first letter of name (uppercased) if src is unset or fails to load (e.g. an expired OAuth profile-photo URL); falls back further to a generic person icon if name is also unset. A broken image never leaves a blank circle. -
<video-player>Video player wrapping a native <video> element (native controls disabled) with the same tokenized transport bar as audio-player — a play/pause icon-button, elapsed/total time, a seekable progress bar, a mute toggle + volume slider — plus a fullscreen toggle. The control bar sits in a persistent strip under the video frame rather than a hover-reveal overlay, so it stays usable for keyboard/touch input without a pointer hover state. -
<vote-control>An up/down vote widget with a live score readout — the "vote an entry up or down toward a promotion threshold" pattern from a public register site, where one member casts a single vote that can be changed or withdrawn at any time. Two native <button>s flank a score; the button matching the user's own cast vote reads as pressed (aria-pressed), and clicking it again withdraws the vote. Set an optional target to render a thin progress meter toward the promotion threshold beneath (vertical) or beside (horizontal) the buttons. -
<weight-bar-chart>Sorted horizontal bar chart of labeled weights (normalized fractions summing to ~1). Bars sort descending — the order IS the priority ranking. Widths scale relative to the largest weight (which fills its track); the percent labels carry the absolute values. Rows are keyed by item id (repeat directive) so a re-render with new weights moves the existing rows; bar widths animate via CSS, re-sorting is instant. -
<window-chrome>Sticky editor/terminal-style chrome bar for the top edge of a page or panel: three decorative traffic-light dots, a filename-style label, and a right-aligned actions slot for controls such as a theme toggle.
Theme with CSS properties
Every component includes token fallbacks and works without global CSS. Override any --ui-* property on an ancestor to apply a theme.
:root {
--ui-primary: #0ea5e9;
--ui-radius: 0.75rem;
}
Machine-readable resources
custom-elements.json- Custom Elements Manifestllms.txt- compact AI-oriented component reference