Componentdata
List
List with dashed, numbered and icon variants plus staggered item entrances and List/ListItem composition.
Preview
Live Preview
- Item OneContent for the first item.
- Item TwoContent for the second item.
- Item ThreeContent for the third item.
Installation
Tokens guide →Add to your project via CLI (zero dependencies, code you own):
npx bigbullui add listOr install the full npm package:
npm install bigbulluiUsage
import { List, ListItem } from "@/components/ui/list";
<List variant="numbered">
<ListItem id="1" title="Doors">Gates open at 19:00.</ListItem>
</List>Source code
list.tsxZero dependencies (only React + utils). Copy and paste directly into your project:
import * as React from "react";
import { cn } from "./lib/utils";
export interface ListItemProps {
id: string;
title?: React.ReactNode;
content?: React.ReactNode;
variant?: "dashed" | "numbered" | "icon";
className?: string;
children?: React.ReactNode;
}
export interface ListProps extends React.HTMLAttributes<HTMLUListElement> {
items?: ListItemProps[];
variant?: "dashed" | "numbered" | "icon";
}
export function ListItem({ id, title, content, variant = "dashed", className, children, ...props }: ListItemProps) {
return (
<li
key={id}
className={cn(
"flex items-start gap-3 animate-[fade-in-up_0.3s_ease-out_both] motion-reduce:animate-none",
variant === "dashed" && "border-l-2 border-dashed border-border pl-4",
className
)}
{...props}
>
{variant === "numbered" && (
<span className="mt-0.5 flex size-5 shrink-0 items-center justify-center rounded-sm bg-secondary font-mono text-[10px] font-bold text-secondary-foreground">
--
</span>
)}
{variant === "icon" && (
<svg aria-hidden="true" viewBox="0 0 12 12" className="mt-1 size-3 shrink-0 text-accent">
<path d="M2 6.5L5 9.5L10 3" stroke="currentColor" strokeWidth="1.5" fill="none" strokeLinecap="round" strokeLinejoin="round" />
</svg>
)}
<span className="min-w-0">
{title && <span className="block font-mono text-[11px] font-bold uppercase tracking-[0.12em] text-foreground">{title}</span>}
<span className="block text-sm text-muted-foreground">{content ?? children}</span>
</span>
</li>
);
}
export function List({ items, variant = "dashed", className, children, ...props }: ListProps) {
const data = items ?? [];
return (
<ul className={cn("space-y-2", className)} {...props}>
{data.length > 0
? data.map((item, index) => (
<li
key={item.id}
className={cn(
"flex items-start gap-3 animate-[fade-in-up_0.3s_ease-out_both] motion-reduce:animate-none",
variant === "dashed" && "border-l-2 border-dashed border-border pl-4"
)}
style={{ animationDelay: `${index * 40}ms` }}
>
{variant === "numbered" && (
<span
className="mt-0.5 flex size-5 shrink-0 items-center justify-center rounded-sm bg-secondary font-mono text-[10px] font-bold text-secondary-foreground animate-[stamp_0.4s_ease-out_both] motion-reduce:animate-none"
style={{ animationDelay: `${index * 40 + 80}ms` }}
>
{String(index + 1).padStart(2, "0")}
</span>
)}
{variant === "icon" && (
<svg aria-hidden="true" viewBox="0 0 12 12" className="mt-1 size-3 shrink-0 text-accent">
<path d="M2 6.5L5 9.5L10 3" stroke="currentColor" strokeWidth="1.5" fill="none" strokeLinecap="round" strokeLinejoin="round" />
</svg>
)}
<span className="min-w-0">
{item.title && <span className="block font-mono text-[11px] font-bold uppercase tracking-[0.12em] text-foreground">{item.title}</span>}
<span className="block text-sm text-muted-foreground">{item.content}</span>
</span>
</li>
))
: children}
</ul>
);
}
Props
| Prop | Type | Description |
|---|---|---|
| items | { id: string; title?: React.ReactNode; content?: React.ReactNode }[] | Data-driven items alternative to children. |
| variant | "dashed" | "numbered" | "icon" | Visual variant; numbered uses mono counter chips. |
| className | string | Additional classes. |
| children | React.ReactNode | ListItem composition alternative. |