Kaart
Een kader met rand voor dashboards, prijsniveaus en productoverzichten — koptekst, inhoud en voettekst met de neobrutalistische harde schaduw.
import { Button } from "@/components/ui/button"
import {
Card,De card groepeert verwante inhoud in een op zichzelf staand kader met optionele slots voor koptekst, inhoud en voettekst. Er zit geen primitive onder — het is kale markup, vormgegeven volgens het neobrutalistische recept: een dikke rand, een harde offset-schaduw en een titel in het koplettertype.
Gebruik deze component bij:
- Dashboardpanelen — statistiektegels, grafieken en activiteitenfeeds geordend in een raster.
- Prijsniveaus — plannaam en prijs in de koptekst, features in de body, de koopknop in de voettekst.
- Losstaande formulieren — inlog-, registratie- en instellingenkaders die een visuele begrenzing nodig hebben.
Installatie#
pnpm dlx shadcn@latest add https://neobrutalism.com/r/base/card.jsonnpx shadcn@latest add https://neobrutalism.com/r/base/card.jsonyarn dlx shadcn@latest add https://neobrutalism.com/r/base/card.jsonbunx --bun shadcn@latest add https://neobrutalism.com/r/base/card.json
Kopieer en plak de volgende code in je project.
import * as React from "react"
import { cn } from "@/lib/utils"
function Card({
className,
size = "default",
...props
}: React.ComponentProps<"div"> & { size?: "default" | "sm" }) {
return (
<div
data-slot="card"
data-size={size}
className={cn(
"group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded border-2 bg-card py-(--card-spacing) text-sm text-card-foreground shadow-md [--card-spacing:--spacing(4)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
className
)}
{...props}
/>
)
}
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-header"
className={cn(
"group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)",
className
)}
{...props}
/>
)
}
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-title"
className={cn(
"cn-font-heading text-base leading-snug font-medium group-data-[size=sm]/card:text-sm",
className
)}
{...props}
/>
)
}
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-description"
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
)
}
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-action"
className={cn(
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
className
)}
{...props}
/>
)
}
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-content"
className={cn("px-(--card-spacing)", className)}
{...props}
/>
)
}
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-footer"
className={cn(
"flex items-center rounded-b-xl border-t-2 bg-muted/50 p-(--card-spacing)",
className
)}
{...props}
/>
)
}
export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardAction,
CardDescription,
CardContent,
}
Werk de import-paden bij zodat ze overeenkomen met je projectstructuur.
Gebruik#
import {
Card,
CardAction,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"<Card>
<CardHeader>
<CardTitle>Card Title</CardTitle>
<CardDescription>Card Description</CardDescription>
<CardAction>Card Action</CardAction>
</CardHeader>
<CardContent>
<p>Card Content</p>
</CardContent>
<CardFooter>
<p>Card Footer</p>
</CardFooter>
</Card>Compositie#
Gebruik de volgende compositie om een Card te bouwen:
Card
├── CardHeader
│ ├── CardTitle
│ ├── CardDescription
│ └── CardAction
├── CardContent
└── CardFooterVoorbeelden#
Grootte#
Gebruik de prop size="sm" om de grootte van de card op klein in te stellen. De variant met kleine grootte gebruikt minder ruimte.
import { ChevronRightIcon } from "lucide-react"
import { Button } from "@/components/ui/button"Ruimte#
Naast de prop size kun je de CSS-variabele --card-spacing gebruiken om de ruimte tussen secties en de inspringing van de card-onderdelen te bepalen.
"use client"
import * as React from "react"Gebruik negatieve marges met -mx-(--card-spacing) om inhoud van rand tot rand te laten lopen terwijl deze uitgelijnd blijft met de inspringing van de card. Wanneer de inhoud van rand tot rand boven een footer staat, gebruik je -mb-(--card-spacing) op CardContent om de tussenruimte tussen secties te verwijderen.
import { Button } from "@/components/ui/button"
import {
Card,Afbeelding#
Voeg een afbeelding toe vóór de card-header om een card met een afbeelding te maken.
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import {RTL#
Om RTL-ondersteuning in Neobrutalism in te schakelen, zie de RTL-configuratiegids.
"use client"
import * as React from "react"Toegankelijkheid#
De card is puur presentationeel — elk onderdeel rendert een kale <div> zonder impliciete rol, dus hij voegt niets toe aan de toegankelijkheidsboom. CardTitle is geen kopelement: nestel er een echte <h2>–<h4> in wanneer de titel in de documentstructuur moet verschijnen. Zet bij klikbare cards de link of knop binnen de card en rek het klikgebied over het hele oppervlak uit — hang nooit een onClick aan de <div> van de card zelf.
API-referentie#
Card#
De component Card is de wortelcontainer voor de card-inhoud.
| Prop | Type | Default |
|---|---|---|
size | "default" | "sm" | "default" |
className | string | - |
CardHeader#
De component CardHeader wordt gebruikt voor een titel, beschrijving en optionele actie.
| Prop | Type | Default |
|---|---|---|
className | string | - |
CardTitle#
De component CardTitle wordt gebruikt voor de titel van de card.
| Prop | Type | Default |
|---|---|---|
className | string | - |
CardDescription#
De component CardDescription wordt gebruikt voor de helptekst onder de titel.
| Prop | Type | Default |
|---|---|---|
className | string | - |
CardAction#
De component CardAction plaatst inhoud rechtsboven in de header (bijvoorbeeld een knop of een badge).
| Prop | Type | Default |
|---|---|---|
className | string | - |
CardContent#
De component CardContent wordt gebruikt voor het hoofdgedeelte van de card.
| Prop | Type | Default |
|---|---|---|
className | string | - |
CardFooter#
De component CardFooter wordt gebruikt voor acties en secundaire inhoud onderaan de card.
| Prop | Type | Default |
|---|---|---|
className | string | - |
Changelog#
Ruimte-variabele#
Als je upgradet van een eerdere versie van de component Card, moet je de volgende updates toepassen om de variabele --card-spacing te gebruiken:
Werk de ruimte-klassen van de Card-wortel bij.
Vervang de hardgecodeerde gap en verticale padding door --card-spacing en stel de waarden voor de standaard- en kleine grootte in op de wortel:
className={cn(
- "group/card flex flex-col gap-4 overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/10 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
+ "group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-xl bg-card py-(--card-spacing) text-sm text-card-foreground ring-1 ring-foreground/10 [--card-spacing:--spacing(4)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
className
)}Werk de ruimte-klassen van CardHeader bij.
Vervang de horizontale padding en randruimte door de gedeelde variabele:
className={cn(
- "group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-4 group-data-[size=sm]/card:px-3 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3",
+ "group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)",
className
)}Werk de ruimte-klassen van CardContent en CardFooter bij.
Gebruik --card-spacing voor de inspringing van de inhoud en de padding van de footer:
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-content"
- className={cn("px-4 group-data-[size=sm]/card:px-3", className)}
+ className={cn("px-(--card-spacing)", className)}
{...props}
/>
)
} className={cn(
- "flex items-center rounded-b-xl border-t bg-muted/50 p-4 group-data-[size=sm]/card:p-3",
+ "flex items-center rounded-b-xl border-t bg-muted/50 p-(--card-spacing)",
className
)}Nadat je deze wijzigingen hebt toegepast, kun je de ruimte van de card aanpassen door --card-spacing op de Card in te stellen met een klasse voor een willekeurige eigenschap:
function Example() {
return <Card className="[--card-spacing:--spacing(6)]">...</Card>
}