Visual guides / Motion
Keep changes easy to follow.
Animate list changes, transitions, and feedback while preserving focus and stable item identities.
Use motion to explain a change: reordered tasks, a new result, or a selected view. Keep routine updates short.
Loading the interactive workbench…
Start building
Load your adapter stylesheet once. Astro needs its client runtime for enhanced interactions; React manages its own lifecycle; Elements needs client registration.
---
// pnpm add @santi020k/lumen-astro
// In your root layout:
import '@santi020k/lumen-astro/styles.css'
import UIPrimitives from '@santi020k/lumen-astro/runtime'
---
<slot />
<UIPrimitives />// pnpm add @santi020k/lumen-react
// In your application entry:
import '@santi020k/lumen-react/styles.css'
// Import components from the public package:
import { MotionGroup, Tabs, Collapsible } from '@santi020k/lumen-react'// pnpm add @santi020k/lumen-elements
// In your client entry, processed by a bundler:
import '@santi020k/lumen-elements/styles.css'
import { defineLumenElements } from '@santi020k/lumen-elements'
defineLumenElements(['MotionGroup', 'Tabs', 'Collapsible'])Starter example
The React example includes local state. Astro and Elements show the component structure; your client code owns data updates and event handlers.
'use client'
import { useState } from 'react'
import { Button, Card, MotionGroup } from '@santi020k/lumen-react'
export function TaskList() {
const [tasks, setTasks] = useState(['Plan', 'Review', 'Ship'])
return <>
<Button onClick={() => setTasks(current => [...current].reverse())}>
Reverse order
</Button>
<MotionGroup duration="standard">
{tasks.map(task => <Card key={task} data-ui-motion-key={task}>{task}</Card>)}
</MotionGroup>
</>
}---
import { Card, MotionGroup } from '@santi020k/lumen-astro'
const tasks = ['Plan', 'Review', 'Ship']
---
<MotionGroup duration="standard">
{tasks.map(task => <Card data-ui-motion-key={task}>{task}</Card>)}
</MotionGroup>
<!-- Your client code owns adding, removing, and reordering these children. --><lumen-motion-group duration="standard">
<lumen-card data-ui-motion-key="plan">Plan</lumen-card>
<lumen-card data-ui-motion-key="review">Review</lumen-card>
<lumen-card data-ui-motion-key="ship">Ship</lumen-card>
</lumen-motion-group>
<!-- Your client code owns adding, removing, and reordering these children. -->Before you ship
- Give every direct child a unique, stable data-ui-motion-key. React keys and DOM motion keys serve different purposes; use both.
- Your application owns the list order and render. Missing or duplicate identities skip ambiguous animation.
- System reduced motion wins. Add data-ui-motion="reduce" to a subtree for an immediate comparison.
- View transitions need one unique view-transition-name per surface. Await asynchronous rendering inside runLumenViewTransition.
Component reference
Find props, events, keyboard behavior, and Astro, React, and Elements examples for each primitive.
For optional Motion and Rive integrations, see the motion playground.