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";
40 components
Component reference
-
<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. -
<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. -
<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-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. -
<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. -
<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. -
<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. -
<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 primary-styled button with a label and chevron 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). -
<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. -
<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). -
<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. -
<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. -
<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. -
<map-circle>A plain circular map marker: a light-to-dark gradient fill with a 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 light-to-dark gradient fill with 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 }). -
<percent-bar-chart>Horizontal bar chart for labeled percentage rows, using D3's linear scale. Each group gets its own labeled row; bars are proportional to percentage of 100. -
<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. -
<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. -
<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. -
<roman-numeral>Converts an integer to a roman numeral inline. -
<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. -
<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%". -
<status-pill>Small colored status pill, optionally with a spinning icon — for task/run states ("Open", "Blocked", "Done") and live-activity indicators ("Running"). -
<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. -
<toast-notification>Fixed-position stack of dismissible notifications, anchored top-right (top-full-width on mobile). 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. Each toast auto-dismisses after duration ms and can also be dismissed via its ✕ button. Appears/disappears instantly — no slide/fade transitions. -
<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. -
<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. -
<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.
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