Layout and data
Surfaces, dividers, tabs, tables, trees, and navigation that structure a page and its data.
Card
Card groups related content on one surface. Compose it from CardHeader, CardTitle, CardDescription,
CardAction, CardContent, and CardFooter. Set padding to sm, md, or lg for a padded card, and surface
to muted or dashed for a quieter one.
import { Plus } from "lucide-react";
import { Button } from "@manta-eu/react/button";
import {
Card,
CardAction,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@manta-eu/react/card";
<Card className="max-w-sm">
<CardHeader>
<CardTitle>Today</CardTitle>
<CardDescription>3 of 5 todos done</CardDescription>
<CardAction>
<Button variant="ghost" icon={Plus} iconOnly aria-label="Add a todo" />
</CardAction>
</CardHeader>
<CardContent className="typography-small">Next up: review the launch checklist.</CardContent>
<CardFooter className="typography-small text-muted-foreground">Updated 5 minutes ago</CardFooter>
</Card>;
Separator
Separator draws a thin line between pieces of content. It is horizontal by default. Set orientation="vertical" to
divide items in a row, and give the row a height.
Write the release notes
import { Separator } from "@manta-eu/react/separator";
<div className="flex max-w-sm flex-col gap-4">
<p className="typography-small">Write the release notes</p>
<Separator />
<div className="flex h-5 items-center gap-4 typography-small text-muted-foreground">
<span>Due Friday</span>
<Separator orientation="vertical" />
<span>High priority</span>
<Separator orientation="vertical" />
<span>Ana</span>
</div>
</div>;
Tabs
Tabs switches between panels that share one place on the page. Give each TabsTrigger and its TabsContent the
same value, and pick the starting tab with defaultValue. Set size="small" for a compact list, and add a
TabCount to show a count in a trigger.
import { TabCount, Tabs, TabsContent, TabsList, TabsTrigger } from "@manta-eu/react/tabs";
<Tabs defaultValue="active">
<TabsList>
<TabsTrigger value="all">
All <TabCount count={5} />
</TabsTrigger>
<TabsTrigger value="active">
Active <TabCount count={2} />
</TabsTrigger>
<TabsTrigger value="completed">
Completed <TabCount count={3} />
</TabsTrigger>
</TabsList>
<TabsContent value="all">Every todo in the project.</TabsContent>
<TabsContent value="active">Todos that still need work.</TabsContent>
<TabsContent value="completed">Todos you have checked off.</TabsContent>
</Tabs>;
Table
SortableTable renders rows from plain columns and rows, and sorts a column when the user clicks its header. Mark
a column numeric to right-align it, and pass cell to render a custom value. For full control, build a TanStack table
and render it with DataTable, or compose Table, TableHeader, TableRow, TableHead, and TableCell by hand.
Todo | Assignee | Status | Hours |
|---|---|---|---|
| Write the release notes | Ana | Active | 2 |
| Review the launch checklist | Marko | Active | 1 |
| Update the pricing page | Ivana | Completed | 3 |
import { SortableTable } from "@manta-eu/react/table";
type Todo = { title: string; assignee: string; status: string; estimate: number };
const todos: Todo[] = [
{ title: "Write the release notes", assignee: "Ana", status: "Active", estimate: 2 },
{ title: "Review the launch checklist", assignee: "Marko", status: "Active", estimate: 1 },
{ title: "Update the pricing page", assignee: "Ivana", status: "Completed", estimate: 3 },
];
<SortableTable
rows={todos}
columns={[
{ key: "title", header: "Todo" },
{ key: "assignee", header: "Assignee" },
{ key: "status", header: "Status" },
{ key: "estimate", header: "Hours", numeric: true },
]}
/>;
Pagination
PaginationBlock shows the current page and buttons to move between pages. It is controlled: pass a zero-based
currentPageIndex, totalPages, and onPageChange. Add showPageSize with pageSize and totalCount to show the
range of rows on the page. Compose Pagination, PaginationContent, and the button parts for a custom layout.
import { useState } from "react";
import { PaginationBlock } from "@manta-eu/react/pagination";
const [page, setPage] = useState(0);
<PaginationBlock
currentPageIndex={page}
totalPages={4}
onPageChange={setPage}
showPageSize
pageSize={25}
totalCount={87}
/>;
Tree
Tree shows nested items that the user expands, collapses, and selects with the mouse or the arrow keys. Pass nodes
with an id, a label, and optional icon, children, defaultExpanded, and disabled. Use defaultSelectedId
on its own, or selectedId with onSelect to control the selection.
- Website
- Update the pricing page
- Publish the launch post
- Mobile app
import { FileText, Folder } from "lucide-react";
import { Tree, type TreeNodeData } from "@manta-eu/react/tree";
const projects: TreeNodeData[] = [
{
id: "website",
label: "Website",
icon: <Folder />,
defaultExpanded: true,
children: [
{ id: "pricing", label: "Update the pricing page", icon: <FileText /> },
{ id: "blog", label: "Publish the launch post", icon: <FileText /> },
],
},
{
id: "mobile",
label: "Mobile app",
icon: <Folder />,
children: [{ id: "onboarding", label: "Redesign onboarding", icon: <FileText /> }],
},
];
<Tree nodes={projects} defaultSelectedId="pricing" aria-label="Projects" className="max-w-xs" />;
Collapsible
Collapsible shows and hides a section when the user clicks its trigger. Put the toggle in CollapsibleTrigger and
the hidden part in CollapsibleContent. Control it with open and onOpenChange, or start it open with
defaultOpen.
import { useState } from "react";
import { ChevronRight } from "lucide-react";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@manta-eu/react/collapsible";
const [open, setOpen] = useState(false);
<Collapsible open={open} onOpenChange={setOpen} className="max-w-sm rounded-lg border border-default-border p-4">
<CollapsibleTrigger className="group flex w-full items-center gap-2">
<span className="typography-small-header">Completed todos</span>
<ChevronRight className="size-4 transition-transform group-data-[state=open]:rotate-90" />
</CollapsibleTrigger>
<CollapsibleContent>
<ul className="mt-3 list-disc space-y-1 pl-5 typography-small">
<li>Update the pricing page</li>
<li>Book the venue</li>
<li>Send the invites</li>
</ul>
</CollapsibleContent>
</Collapsible>;
Breadcrumbs
Breadcrumbs shows where the current page sits in the hierarchy. Pass items with a label and an href or
onClick. The last item marks the current page. Items with an href render a plain <a>, so no router is needed.
Pass renderLink to use your router’s link instead.
import { Home, ListTodo } from "lucide-react";
import { Breadcrumbs } from "@manta-eu/react/breadcrumbs";
<Breadcrumbs
items={[
{ label: "Home", href: "#", icon: <Home /> },
{ label: "Website", href: "#", icon: <ListTodo /> },
{ label: "Update the pricing page" },
]}
/>;