Detent web components
By Shane Logsdon

Navigation

Animated Tabs

Implemented

Layout-spring sliding active pill indicator

detent-animated-tabs

Port status
Catalog status
implemented
Origin
upstream
Phase
2
Wave
phase-2-navigation
Group
Navigation

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

Variants

Recorded states

  • active recorded state; no setter

Usage

Import

import '/components/animated-tabs/define.js';

// or register it yourself
import { DetentAnimatedTabs } from '/components/animated-tabs/animated-tabs.js';

Attributes

  • active-tab
  • default-tab
  • layout-id
  • render-content
  • tabs-container-class-name
  • variant

Properties

  • tabs
  • activeTab
  • defaultTab
  • variant
  • renderContent
  • layoutId
  • onChange

Slots

No slots are recorded for this component.

Events

  • detent-change — { id: string }

Example

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

<detent-animated-tabs
  active-tab
  default-tab
  layout-id
  render-content
  tabs-container-class-name
  variant
></detent-animated-tabs>

Property-only values

const element = document.querySelector('detent-animated-tabs');
if (element !== null) {
  // tabs: TabItem[]
  element.tabs = [];
  // onChange: (id: string) => void
  element.onChange = () => {};
}

Source

The pinned upstream source for this row:

  • src/components/ui/AnimatedTabs.tsx sha256 53fb159bd6e4…

Native files

The native module and its artifacts:

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

API

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

Attributes

Attributes
AttributePropertyTypeDefaultNotes
active-tab———Recorded in the catalog as an attribute.
default-tabdefaultTabstringtabs[0].idKebab-case attribute; camelCase property.
layout-id———Recorded in the catalog as an attribute.
render-content———Recorded in the catalog as an attribute.
tabs-container-class-name———Recorded in the catalog as an attribute.
variant———Recorded in the catalog as an attribute.

Properties

Properties
PropertyTypeDefaultNotes
tabsTabItem[][]Property-only: assign from script; not accepted as an attribute.
activeTab——Recorded in the catalog without a top-level type; pinned from source when the row is ported.
defaultTabstringtabs[0].idProperty-only: assign from script; not accepted as an attribute.
variant——Recorded in the catalog without a top-level type; pinned from source when the row is ported.
renderContent——Recorded in the catalog without a top-level type; pinned from source when the row is ported.
layoutId——Recorded in the catalog without a top-level type; pinned from source when the row is ported.
onChange(id: string) => voidundefinedProperty-only: assign from script; not accepted as an attribute.

Events

Events
EventUpstream propPayload typeNotes
detent-changeonChange(id: string) => 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.
  • React state/hooks replaced by element-owned state with pre-upgrade property preservation.
  • `layoutId` no longer joins a Framer Motion shared layout - observable as `data-layout-id` on `part="tab-indicator"`, motion scoped to the element's own tablist.
  • `tabsContainerClassName` cannot cross the shadow boundary, so its tokens become extra CSS part names on `part="tablist"`; `className` maps to `part="root"`.
  • `TabItem.icon`/`content` were React nodes and are text (no slot invented, no HTML parsing).
  • Arrow-key selection added: the row records tablist/tab/tabpanel roles plus keyboard arrow navigation as obligations, upstream had plain buttons.
  • `render-content` resolves true, is reflected while connected, and the property is the opt-out (PC-3.2), so `render-content="false"` is still true.
  • The panel cross-fades in with springGentle and AnimatePresence exit-then-enter is dropped (a stale labelled panel would otherwise remain); the indicator travels on two axes with springMorph (220/32/1) via the shared spring helper.

What it does

A tablist with a sliding indicator and cross-faded panels; the indicator follows the selected tab with a short spring.

Upstream behaviour
  • Shared layout active pill with spring easing
  • Independent content animation cross-fade
  • Badge count support for notifications
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.
  • React state/hooks replaced by element-owned state with pre-upgrade property preservation.
  • `layoutId` no longer joins a Framer Motion shared layout - observable as `data-layout-id` on `part="tab-indicator"`, motion scoped to the element's own tablist.
  • `tabsContainerClassName` cannot cross the shadow boundary, so its tokens become extra CSS part names on `part="tablist"`; `className` maps to `part="root"`.
  • `TabItem.icon`/`content` were React nodes and are text (no slot invented, no HTML parsing).
  • Arrow-key selection added: the row records tablist/tab/tabpanel roles plus keyboard arrow navigation as obligations, upstream had plain buttons.
  • `render-content` resolves true, is reflected while connected, and the property is the opt-out (PC-3.2), so `render-content="false"` is still true.
  • The panel cross-fades in with springGentle and AnimatePresence exit-then-enter is dropped (a stale labelled panel would otherwise remain); the indicator travels on two axes with springMorph (220/32/1) via the shared spring helper.
Previous: Animated Number Morph Next: Avatar Stack

Docs

Components

Project