Lists
ListCut: new items fly in from the button that added them, removed ones fold away, and moved ones glide.
- Write the release notes
- Review the onboarding flow
- Reply to Priya
In a stock list, a new item appears from nowhere, a deleted one vanishes and everything below jumps up, and a reorder teleports every row. ListCut gives each of those changes a motion you can follow.
Install
npx shadcn add @keyframery/list-cutIf your project doesn't know @keyframery yet, do the Quick start first.
Use
Replace your list and its items with ListCut and ListCut.Item, and give each item the same id you use as its key:
import { ListCut } from "@/components/keyframery/list-cut"
<ListCut as="ul" className="space-y-2">
{messages.map((m) => (
<ListCut.Item key={m.id} id={m.id} as="li">
{m.text}
</ListCut.Item>
))}
</ListCut>It works with any data source, because it only compares ids between renders. For a table, use ListCut as="tbody" with ListCut.Item as="tr".
You should see
- Add an item with a button: it flies out of that button into its place.
- Add an item with no button involved, for example from the server: it rises in.
- Remove an item: it folds away, and the items below slide up a moment later.
- Reorder: every item glides to its new place.
Options
Prop
Type
ListCut.Item:
Prop
Type
Both pass any other props, such as className or aria-label, to their element.
Good to know
- The first render never animates.
- Only items in or near the viewport animate, so long lists stay fast.
- Timing: an added item flies in over 480 ms; a removed one folds away and the items below follow 60 ms later; a moved one glides over 320 ms.
- A removed table row folds inside a one-row table that keeps your column widths.
In film, a new item flying from the button is a cut on action, and a removed item leaving before the rest move up is an L-cut.