Detent web components
By Shane Logsdon

Feedback & status

Loader

Implemented

Calm continuous loading feedback

detent-loader

Port status
Catalog status
implemented
Origin
upstream
Phase
2
Wave
phase-2-feedback
Group
Feedback & status

3.2 KB gzip for the class module

Variants

Recorded states

  • loading recorded state; no setter
  • dark theme recorded state; no setter
  • reduced motion recorded state; no setter

Usage

Import

import '/components/loader/define.js';

// or register it yourself
import { DetentLoader } from '/components/loader/loader.js';

Attributes

  • color
  • label
  • reduce-motion
  • size
  • variant

Properties

  • variant
  • size
  • label
  • color
  • reduceMotion

Slots

No slots are recorded for this component.

Events

No events are recorded for this component.

Example

Runnable example: site/examples/loader.ts. The snippet below is generated from the catalogued attributes.

<detent-loader
  color="currentColor"
  label="Loading..."
  reduce-motion
  size="32"
  variant="arc"
></detent-loader>

Source

The pinned upstream source for this row:

  • src/components/ui/Loader.tsx sha256 cf1330cc88e9…

Native files

The native module and its artifacts:

  • src/components/loader/loader.ts
  • src/components/loader/styles.css
  • src/components/loader/define.ts
  • docs/components/loader.md
  • site/examples/loader.ts
  • tests/browser/loader.spec.ts
  • evidence/components/loader.md

API

Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.

Attributes

Attributes
AttributePropertyTypeDefaultNotes
colorcolorstring'currentColor'Kebab-case attribute; camelCase property.
labellabelstring'Loading...'Kebab-case attribute; camelCase property.
reduce-motionreduceMotionbooleanfalsePresence semantics: present means true, absent means false.
sizesizenumber32Kebab-case attribute; camelCase property.
variantvariant'arc' | 'dots' | 'line' | 'rings''arc'Kebab-case attribute; camelCase property.

Properties

Properties
PropertyTypeDefaultNotes
variant'arc' | 'dots' | 'line' | 'rings''arc'Property-only: assign from script; not accepted as an attribute.
sizenumber32Property-only: assign from script; not accepted as an attribute.
labelstring'Loading...'Property-only: assign from script; not accepted as an attribute.
colorstring'currentColor'Property-only: assign from script; not accepted as an attribute.
reduceMotionbooleanfalseProperty-only: assign from script; not accepted as an attribute.

Events

No custom events are recorded for this component.

Slots

No slots are recorded for this component.

CSS customisation

  • `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
  • Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
  • React state/hooks replaced by element-owned state with pre-upgrade property preservation.
  • Colours are theme-token driven (`--detent-color-text`, `color-mix` track) instead of the upstream dark-only literals `text-[#FAFAFA]`, `#1F1F1F`, `#141414` (PC-9.5/PC-12.6); measured 16.47-17.93:1 against the page background in both schemes.
  • `size` and `color` are applied through documented custom properties (`--detent-loader-size`, `--detent-loader-color`) written as inline styles, because CSS cannot read an attribute value as a length.
  • The label is a single visually hidden text node inside `role="status"`; upstream rendered both `aria-label` and an sr-only span (duplicate announcement).
  • Framer Motion timelines are CSS keyframes with the upstream durations/delays/easings (2.5s spin, 1.4s dots with 0.22s stagger, 1.8s slide, 2.2s rings with 0.9s stagger); reduced motion keeps the upstream opacity pulse.
  • Invalid `size`/`variant` values fall back or clamp with a development warning instead of being passed through to inline styles.

What it does

Four animated loading indicators — a rotating arc, breathing dots, a sliding line and expanding rings — with a configurable size, paint colour and accessible label.

Upstream behaviour
  • 4 refined motion variants: rotating arc, breathing dots, sliding line, and expanding concentric rings
  • Configurable dimensions and stroke colors with seamless dark mode support
  • Accessible role="status" and aria-busy telemetry without screen reader interruption
  • Automatic reduced-motion adaptation for sensitive viewers
Differences from upstream
  • `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
  • Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
  • React state/hooks replaced by element-owned state with pre-upgrade property preservation.
  • Colours are theme-token driven (`--detent-color-text`, `color-mix` track) instead of the upstream dark-only literals `text-[#FAFAFA]`, `#1F1F1F`, `#141414` (PC-9.5/PC-12.6); measured 16.47-17.93:1 against the page background in both schemes.
  • `size` and `color` are applied through documented custom properties (`--detent-loader-size`, `--detent-loader-color`) written as inline styles, because CSS cannot read an attribute value as a length.
  • The label is a single visually hidden text node inside `role="status"`; upstream rendered both `aria-label` and an sr-only span (duplicate announcement).
  • Framer Motion timelines are CSS keyframes with the upstream durations/delays/easings (2.5s spin, 1.4s dots with 0.22s stagger, 1.8s slide, 2.2s rings with 0.9s stagger); reduced motion keeps the upstream opacity pulse.
  • Invalid `size`/`variant` values fall back or clamp with a development warning instead of being passed through to inline styles.
Previous: Live Line Chart Next: LockInput

Docs

Components

Project