Detent web components
By Shane Logsdon

Feedback & status

Intro Loader

Implemented

Apple-style multilingual greeting welcome splash

detent-intro-loader

Port status
Catalog status
implemented
Origin
upstream
Phase
4
Wave
phase-4-cinematic
Group
Feedback & status

7.4 KB gzip for the class module · inlines the shared spring

Variants

This loader is the full-screen default: it opens as a native modal <dialog> (Escape or the Skip button completes it once and focus returns to the page). The one in the preview is the inline documentation mode: it cycles the same greetings in normal flow and shows Replay Intro when it finishes. Both emit exactly one composed detent-complete with an empty detail.

Reduced motion is honoured at runtime as well: with prefers-reduced-motion: reduce both loaders complete immediately, with no timer and no animation frame. Visible demonstration data: the greeting list comes from the pinned upstream defaults.

Recorded states

  • closed recorded state; no setter
  • reduced motion recorded state; no setter
  • completed recorded state; no setter

Usage

Import

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

// or register it yourself
import { DetentIntroLoader } from '/components/intro-loader/intro-loader.js';

Attributes

  • allow-skip
  • full-screen
  • interval-ms
  • show-lang-badge
  • show-progress
  • speed-multiplier

Properties

  • greetings
  • onComplete

Slots

No slots are recorded for this component.

Events

  • detent-complete — {}

Example

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

<detent-intro-loader
  allow-skip
  full-screen
  interval-ms="240"
  show-lang-badge
  show-progress
  speed-multiplier="1"
></detent-intro-loader>

Property-only values

const element = document.querySelector('detent-intro-loader');
if (element !== null) {
  // greetings: (string | GreetingItem)[]
  element.greetings = () => {};
  // onComplete: () => void
  element.onComplete = () => {};
}

Source

The pinned upstream source for this row:

  • src/components/ui/IntroLoader.tsx sha256 be9623d2721e…

Native files

The native module and its artifacts:

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

API

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

Attributes

Attributes
AttributePropertyTypeDefaultNotes
allow-skipallowSkipbooleantruePresence semantics: present means true, absent means false.
full-screenfullScreenbooleantruePresence semantics: present means true, absent means false.
interval-msintervalMsnumber240Kebab-case attribute; camelCase property.
show-lang-badgeshowLangBadgebooleantruePresence semantics: present means true, absent means false.
show-progressshowProgressbooleantruePresence semantics: present means true, absent means false.
speed-multiplierspeedMultipliernumber1Kebab-case attribute; camelCase property.

Properties

Properties
PropertyTypeDefaultNotes
greetings(string | GreetingItem)[]['Hello', 'Hola', 'Bonjour', ...]Property-only: assign from script; not accepted as an attribute.
onComplete() => voidundefinedProperty-only: assign from script; not accepted as an attribute.

Events

Events
EventUpstream propPayload typeNotes
detent-completeonComplete() => voidComposed, bubbles; fires only for a user action.

Slots

No slots are recorded for this component.

CSS customisation

  • React callback props become typed composed CustomEvents; programmatic state assignment emits none.
  • Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
  • `lucide-react` icon components replaced with local SVG assets (ISC notice retained).
  • React state/hooks replaced by element-owned state with pre-upgrade property preservation.
  • The 650 ms AnimatePresence exit transition is removed: the overlay closes immediately on completion or skip so focus returns without a dead window (PC-12.4); the greeting entry and replay entrance are preserved.
  • The visible language badge is rendered; the pinned source destructured showLangBadge and typed GreetingItem.lang but never rendered a badge.
  • The visible greeting is aria-hidden and the live region is the single announcement, where upstream rendered the greeting twice.
  • A native modal dialog replaces the role=dialog div: real top layer, real inertness, native cancel on Escape, and aria-modal=true only in full-screen mode.
  • Reduced motion completes in a microtask with no timer, and a runtime preference change also completes immediately.
  • Empty or invalid greetings fall back to the pinned default list instead of crashing on undefined.
  • The ESC skip hint hides below 640 px while the button keeps its accessible name.
  • showLangBadge, fullScreen, showProgress and allowSkip default true and are reflected while connected; the property is the opt-out (PC-3.2).
  • Progress track and boundaries use #6b6b6b/#8a8a8a instead of the upstream hairlines that measured below the 1.4.11 3:1 threshold (PC-12.6).

What it does

An Apple-style multilingual welcome splash: it cycles greetings, tracks the sequence with a hairline progress bar, can be skipped with Escape or a button, and completes exactly once.

Upstream behaviour
  • Rapid multilingual greeting cycling inspired by Apple OS welcome splash
  • Fluid blur, scale, and opacity entry transitions calibrated with cubic-bezier curves
  • Apple-style hairline progress indicator tracking sequence completion
  • Keyboard and tactile skip mechanism (ESC key or dedicated discrete button)
  • Full accessibility support with aria-live announcements and reduced-motion fallbacks
  • Supports both full-screen initial overlay and inline documentation preview modes
Differences from upstream
  • React callback props become typed composed CustomEvents; programmatic state assignment emits none.
  • Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
  • `lucide-react` icon components replaced with local SVG assets (ISC notice retained).
  • React state/hooks replaced by element-owned state with pre-upgrade property preservation.
  • The 650 ms AnimatePresence exit transition is removed: the overlay closes immediately on completion or skip so focus returns without a dead window (PC-12.4); the greeting entry and replay entrance are preserved.
  • The visible language badge is rendered; the pinned source destructured showLangBadge and typed GreetingItem.lang but never rendered a badge.
  • The visible greeting is aria-hidden and the live region is the single announcement, where upstream rendered the greeting twice.
  • A native modal dialog replaces the role=dialog div: real top layer, real inertness, native cancel on Escape, and aria-modal=true only in full-screen mode.
  • Reduced motion completes in a microtask with no timer, and a runtime preference change also completes immediately.
  • Empty or invalid greetings fall back to the pinned default list instead of crashing on undefined.
  • The ESC skip hint hides below 640 px while the button keeps its accessible name.
  • showLangBadge, fullScreen, showProgress and allowSkip default true and are reflected while connected; the property is the opt-out (PC-3.2).
  • Progress track and boundaries use #6b6b6b/#8a8a8a instead of the upstream hairlines that measured below the 1.4.11 3:1 threshold (PC-12.6).
Previous: Timeline Next: Expanding Search Field

Docs

Components

Project