Detent web components
By Shane Logsdon

Feedback & status

Notice Toast

Implemented

Toast that slides in and settles

detent-notice-toast

Port status
Catalog status
implemented
Origin
upstream
Phase
3
Wave
phase-3-overlays
Group
Feedback & status
Show toast

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

Variants

The toast is anchored to the viewport (like upstream), so this preview opens one on demand. Hover or focus it to freeze the countdown bar.

success · bottom-right info · bottom-center warning · top-right error · top-left custom icon · top-center

No toast opened yet.

Recorded states

  • hover recorded state; no setter
  • open recorded state; no setter
  • paused recorded state; no setter
  • dark theme recorded state; no setter

Usage

Import

import '/components/notice-toast/define.js';

// or register it yourself
import { DetentNoticeToast } from '/components/notice-toast/notice-toast.js';

Attributes

  • description
  • duration
  • open
  • position
  • show-progress
  • title
  • variant

Properties

  • onDismiss
  • position

Slots

  • icon

Events

  • detent-dismiss — {}

Example

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

<detent-notice-toast
  description
  duration="4000"
  open
  position="bottom-center"
  show-progress
  title
  variant="default"
></detent-notice-toast>

Property-only values

const element = document.querySelector('detent-notice-toast');
if (element !== null) {
  // onDismiss: () => void
  element.onDismiss = () => {};
  // position: VelocityToastPosition
  element.position = 'bottom-center';
}

Source

The pinned upstream source for this row:

  • src/components/ui/VelocityToast.tsx sha256 4bc21f48fca4…

Native files

The native module and its artifacts:

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

API

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

Attributes

Attributes
AttributePropertyTypeDefaultNotes
descriptiondescriptionstringundefinedKebab-case attribute; camelCase property.
durationdurationnumber4000Kebab-case attribute; camelCase property.
openopenbooleanundefinedPresence semantics: present means true, absent means false.
positionpositionVelocityToastPosition'bottom-center'Kebab-case attribute; camelCase property.
show-progressshowProgressbooleantruePresence semantics: present means true, absent means false.
titletitlestringundefinedKebab-case attribute; camelCase property.
variantvariant'default' | 'success' | 'warning' | 'error' | 'info''default'Kebab-case attribute; camelCase property.

Properties

Properties
PropertyTypeDefaultNotes
onDismiss() => voidundefinedProperty-only: assign from script; not accepted as an attribute.
positionVelocityToastPosition'bottom-center'Property-only: assign from script; not accepted as an attribute.

Events

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

Slots

Slots
SlotNotes
iconConsumer content; rendered through a slot, never re-created.

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.
  • onDismiss becomes detent-dismiss with detail: {}; className becomes parts and custom properties; icon becomes the icon slot (an empty slot element suppresses the variant icon, the native form of icon={false}).
  • The toast is position: fixed inside the host, not in the top layer. A native dialog would make it modal and a popover would light-dismiss it on an outside click. Recorded limitation: an ancestor with transform, filter, contain or perspective becomes the containing block, so the toast would be anchored to that ancestor instead of the viewport (PC-9.8).
  • Framer Motion's springSnappy entry/exit becomes the shared spring helper with the same pinned values (380/30/0.5) driving one progress value, so an interrupted exit reverses from where it is. Entry y: ±22 px / scale: 0.94 and exit y: ±12 px / scale: 0.96 match upstream; reduced motion skips both.
  • The progress bar is a direct requestAnimationFrame width update through the upstream pow(1.05) easing instead of a useMotionValue + useTransform pair. The eased value is asserted against the linear value in the spec.
  • lucide-react icons (Check, X, AlertTriangle, AlertCircle, Info) become local decorative inline SVGs (upstream ISC notice retained in THIRD_PARTY_NOTICES.md).
  • Accessibility additions: Escape inside the toast dismisses it, focus inside pauses the countdown, a dismissal moves focus out of the toast, and the close button's focus ring comes from --detent-focus-ring instead of a Tailwind focus-ring utility.
  • open has no documented default in the row and upstream required the prop, so the native default is “closed until open is set”; the reflected attribute is the observable state.
  • The entry offset animation is not applied while reduced motion is on, and the final state is the same one a settled spring produces (no leftover transform).

What it does

A toast that enters with a higher initial velocity, settles on a snappy spring, and drains a countdown bar with a slight ease-in so the last part of the window feels decisive.

Upstream behaviour
  • Entry animation starts further out (y: 22px) for higher perceived velocity, then springs to rest
  • Progress indicator uses a slight ease-in (pow 1.05) so the final 10% feels decisive
  • Hover pauses progress without visual jump; resume picks up from the remaining time
  • 6 position presets, 5 variant tones, optional custom icon
  • Light/dark theme aware — works in both palettes
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.
  • onDismiss becomes detent-dismiss with detail: {}; className becomes parts and custom properties; icon becomes the icon slot (an empty slot element suppresses the variant icon, the native form of icon={false}).
  • The toast is position: fixed inside the host, not in the top layer. A native dialog would make it modal and a popover would light-dismiss it on an outside click. Recorded limitation: an ancestor with transform, filter, contain or perspective becomes the containing block, so the toast would be anchored to that ancestor instead of the viewport (PC-9.8).
  • Framer Motion's springSnappy entry/exit becomes the shared spring helper with the same pinned values (380/30/0.5) driving one progress value, so an interrupted exit reverses from where it is. Entry y: ±22 px / scale: 0.94 and exit y: ±12 px / scale: 0.96 match upstream; reduced motion skips both.
  • The progress bar is a direct requestAnimationFrame width update through the upstream pow(1.05) easing instead of a useMotionValue + useTransform pair. The eased value is asserted against the linear value in the spec.
  • lucide-react icons (Check, X, AlertTriangle, AlertCircle, Info) become local decorative inline SVGs (upstream ISC notice retained in THIRD_PARTY_NOTICES.md).
  • Accessibility additions: Escape inside the toast dismisses it, focus inside pauses the countdown, a dismissal moves focus out of the toast, and the close button's focus ring comes from --detent-focus-ring instead of a Tailwind focus-ring utility.
  • open has no documented default in the row and upstream required the prop, so the native default is “closed until open is set”; the reflected attribute is the observable state.
  • The entry offset animation is not applied while reduced motion is on, and the final state is the same one a settled spring produces (no leftover transform).
Previous: Accordion Next: Wallet Balance

Docs

Components

Project