Detent web components
By Shane Logsdon

Media & effects

Folder Cards

Implemented

macOS folder icon with fluid spring card reveal

detent-folder-cards

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

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

Variants

Hover the folder to lift the peeking cards and tilt the flap; click it (or press Enter/Space) to open the card grid. Focus moves to Close when the folder opens, and Escape or Close collapses it again with focus back on the folder. The row records no events, so nothing is dispatched.

Demonstration data: the open folder shows a labelled demo list, not consumer content. With prefers-reduced-motion: reduce the parallax is removed entirely (no spring, no animation frame) and both states are reached instantly.

Recorded states

  • hover recorded state; no setter
  • expanded recorded state; no setter
  • reduced motion recorded state; no setter

Usage

Import

import '/components/folder-cards/define.js';

// or register it yourself
import { DetentFolderCards } from '/components/folder-cards/folder-cards.js';

Attributes

  • default-open
  • folder-category
  • folder-title
  • is-peeked

Properties

  • items

Slots

No slots are recorded for this component.

Events

No events are recorded for this component.

Example

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

<detent-folder-cards
  default-open
  folder-category="Pipeline"
  folder-title="Components"
  is-peeked
></detent-folder-cards>

Property-only values

const element = document.querySelector('detent-folder-cards');
if (element !== null) {
  // items: MacOSFolderCardItem[]
  element.items = [];
}

Source

The pinned upstream source for this row:

  • src/components/ui/MacOSFolderCards.tsx sha256 32967c238837…

Native files

The native module and its artifacts:

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

API

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

Attributes

Attributes
AttributePropertyTypeDefaultNotes
default-opendefaultOpenbooleanfalsePresence semantics: present means true, absent means false.
folder-categoryfolderCategorystring'Pipeline'Kebab-case attribute; camelCase property.
folder-titlefolderTitlestring'Components'Kebab-case attribute; camelCase property.
is-peeked———Recorded in the catalog as an attribute.

Properties

Properties
PropertyTypeDefaultNotes
itemsMacOSFolderCardItem[]demo itemsProperty-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

  • 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.
  • One static tree and a deliberate focus contract replace the AnimatePresence subtree swap that dropped focus to body; the inactive section is hidden and focus moves into the expanded view and back on close.
  • folderCategory is rendered as the header category breadcrumb (hidden when empty); the pinned source declared it but never rendered it.
  • items[].icon is a glyph name over four local SVGs instead of a ReactNode; unknown names fall back to layers.
  • VelocityAwareScrollCards is dropped because it was a deprecation alias of the same component; the upstream alias stays in upstreamAliases.
  • Collapse is immediate so the documented focus return is not delayed; the panel and card entrance animation is kept.
  • The expanded panel and card entrance use WAAPI with the same 260 ms curve and 30 ms stagger; hover and parallax keep the pinned springs.
  • Boundary colours are raised to #6b6b6b and card meta text to #a1a1a1 for 1.4.11 and 1.4.3; the card grid stays a fixed dark surface in both schemes.
  • items is validated as plain data and the built-in list is upstream demonstration data.
  • The trigger has no hand-written aria-label: its accessible name is computed from its visible title and count plus a visually hidden hint, so the visible text cannot fall out of the name (WCAG 2.5.3). The decorative folder art stays aria-hidden.

What it does

A porcelain-white macOS folder that lifts its three peeking cards under the pointer and opens into a card grid.

Upstream behaviour
  • Porcelain-white macOS folder silhouette with 3D flap hinge and cards peeking from pocket
  • Interactive hover parallax lifts cards and tilts folder flap in 3D perspective
  • Opens into a minimal, seamless card grid with Apple fluid spring easing
  • Crisp pure white icons and EasyUI dark surface harmony
Differences from upstream
  • 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.
  • One static tree and a deliberate focus contract replace the AnimatePresence subtree swap that dropped focus to body; the inactive section is hidden and focus moves into the expanded view and back on close.
  • folderCategory is rendered as the header category breadcrumb (hidden when empty); the pinned source declared it but never rendered it.
  • items[].icon is a glyph name over four local SVGs instead of a ReactNode; unknown names fall back to layers.
  • VelocityAwareScrollCards is dropped because it was a deprecation alias of the same component; the upstream alias stays in upstreamAliases.
  • Collapse is immediate so the documented focus return is not delayed; the panel and card entrance animation is kept.
  • The expanded panel and card entrance use WAAPI with the same 260 ms curve and 30 ms stagger; hover and parallax keep the pinned springs.
  • Boundary colours are raised to #6b6b6b and card meta text to #a1a1a1 for 1.4.11 and 1.4.3; the card grid stays a fixed dark surface in both schemes.
  • items is validated as plain data and the built-in list is upstream demonstration data.
  • The trigger has no hand-written aria-label: its accessible name is computed from its visible title and count plus a visually hidden hint, so the visible text cannot fall out of the name (WCAG 2.5.3). The decorative folder art stays aria-hidden.
Previous: Login Next: Magnetic Button

Docs

Components

Project