A playful list for pinning and unpinning items, with smooth animated transitions as items move between groups.
Installation
pnpm dlx shadcn@latest add "https://narakcode.dev/r/pin-list.json"
Usage
First, define the items you want to display. Each item must conform to the PinListItem type, requiring an id, name, info, an icon, and a boolean pinned state.
import { Bug, Code, Cpu, Rocket, UploadCloud } from "lucide-react"
import { PinList } from "@/components/pin-list"
const ITEMS = [
{
id: 1,
name: "Code Your Dreams",
info: "Every keystroke counts · Never stop building",
icon: Rocket,
pinned: true,
},
{
id: 2,
name: "Focus Mode",
info: "Deep work zone · Flow state all day",
icon: Cpu,
pinned: false,
},
]
export default function PinListDemo() {
return (
<PinList
items={ITEMS}
labels={{ pinned: "Favorites", unpinned: "Others" }}
/>
)
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
items | PinListItem[] | (required) | The array of items to display in the list. |
className | string | "" | Additional CSS classes for the root component element. |
labelClassName | string | "" | Additional CSS classes for the section labels. |
pinnedSectionClassName | string | "" | Additional CSS classes for the wrapper of the pinned items. |
unpinnedSectionClassName | string | "" | Additional CSS classes for the wrapper of the unpinned items. |
labels | { pinned?: string; unpinned?: string; } | { pinned: "Pinned", ... } | Custom text for the pinned and unpinned section labels. |
transition | Transition | { type: "spring", ... } | Framer Motion transition object for item layout animations. |
labelMotionProps | HTMLMotionProps<"p"> | { initial: ..., ... } | Framer Motion props for the section label animations. |
zIndexResetDelay | number | 500 | Delay in ms to reset z-index after an animation. |
Types
type PinListItem = {
id: number
name: string
info: string
icon: React.ElementType // e.g. from lucide-react
pinned: boolean // Initial pinned state
}How It Works
- Layout Animations: The component heavily relies on
motion/react(specifically<LayoutGroup>and thelayoutprop) to smoothly animate items between the pinned and unpinned groups. - Smart Z-Indexing: When an item transitions between groups, it dynamically updates its
z-indexto ensure it floats above the rest of the list without clipping. ThezIndexResetDelayensures the stacking context resets right after the animation completes. - Optimized Re-renders: The list automatically manages internal state derived from the
itemsprop, removing the need for you to pass external state handlers for the pin/unpin interactions.