Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelogContact
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCountry SelectCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputEmoji PickerFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone SelectTree Select
Forms
Address InputBooking WidgetCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage GalleryImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadChat WidgetConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeTerminalText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowOrder History PagePost Listing WizardPricing PageProfile PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAgency PageAI Product PageAppointment Booking PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageHome Services PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePortfolio PagePress PageProduct Tour PagePromo PageReal Estate PageReferral PageResearch Report PageRestaurant PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageStorefront PageSwitch PageTemplate Gallery PageTravel PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

Layout

Card

Layout

Card React component for Tailwind CSS v4

App ShellCollapsible
Live props
Content
title
description
Appearance
variant
tone
color
size
radius
Behavior
interactive
asChild
State
selected
disabled
Layout
orientation
divided
Code
import { Card } from "@/components/ui/card"

<Card />
  1. Home
  2. Components
  3. Layout
  4. Card
Free

Card React component for Tailwind CSS v4

v1.0.0·Added in 1.0.0

A React card component for listings, stats, settings and plans: media, header, body and footer parts, and a lift-and-press mode.

A plain card just holds content. An interactive card lifts 2px on hover with a deeper shadow while its photo zooms in a touch, and dips to 98% while pressed; pressing a button inside it (a like, a menu) presses only that button. Link cards are one Tab stop with the focus ring around the whole card: Enter opens them, a click anywhere follows the link, and the buttons on the photo, in the header and in the footer keep working. A card with onClick is a real button to the keyboard (Enter or Space). Selectable cards built on a radio group move with the arrow keys and show a ring in the tone. A disabled card dims and leaves the tab order. Phones get no hover lift, only the press, and horizontal cards stack their photo on top below 640px.

Card is a free React component in the React layout components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add card, together with Tones and UIProvider and the npm package @radix-ui/react-slot.

Add to a project

Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup

npx wingo-ui@latest add card

Usage

Import Card from @/components/ui/card.

import { Heart } from "lucide-react"
import { Avatar } from "@/components/ui/avatar"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Card, CardFooter, CardLink, CardMedia } from "@/components/ui/card"

export function ListingCard({ onSave }: { onSave: () => void }) {
  return (
    <Card
      className="max-w-sm"
      media={
        <CardMedia src="/demo/apartment.jpg">
          <Badge variant="solid" size="sm" className="absolute start-3 top-3">New</Badge>
          <Button size="icon-sm" variant="soft" radius="full" aria-label="Save" onClick={onSave} className="absolute end-3 top-3">
            <Heart />
          </Button>
        </CardMedia>
      }
      title={<CardLink href="/listings/10482">2-bedroom apartment, Park Slope</CardLink>}
      description="Brooklyn · 580 sq ft · floor 3 of 4"
      footer={
        <CardFooter align="between">
          <span className="text-[17px] font-semibold">$445,000</span>
          <span className="flex items-center gap-2 text-[13px] text-muted-foreground">
            <Avatar src="/demo/ana-pop.jpg" name="Anna Price" size="xs" /> today, 2:20 PM
          </span>
        </CardFooter>
      }
    />
  )
}

Props

  • titledefault ""
    ReactNode

    Simple API: the heading (an h3). Pass a CardLink here to make the whole card a link (interactive turns on by itself). The demo shows its sample listing title while empty.

  • descriptiondefault ""
    ReactNode

    Simple API: the muted line under the title. The demo shows its sample while empty.

  • variantdefault "elevated"
    "elevated" | "outline" | "soft" | "ghost"

    elevated is a raised white panel (the surface token with its shadow), outline a hairline frame, soft the flat gray tile (tinted by a tone), ghost only padding, for lists of cards on a panel. Deviation: elevated is a card-only value.

  • tonedefault "neutral"
    "neutral" | "brand" | "success" | "warning" | "danger" | "info"

    Tints soft and outline cards (the title takes the tone color) and colors the selected ring. Elevated and ghost cards only show it when selected.

  • colordefault ""
    string

    Any CSS color. Replaces the tone: a 14% tint on soft cards, the border on outline cards, the selected ring.

  • sizedefault "md"
    "sm" | "md" | "lg"

    Padding 16 / 20 / 24px (md and lg use one step less on phones), 12 / 16 / 20px between parts, and the title size. Media bleeds and divided footers follow.

  • radiusdefault "md"
    "none" | "sm" | "md" | "lg" | "full"

    Corner radius: 0, 12, 16 or 24px; full falls back to 24px. Inset media takes the radius minus the padding.

  • interactivedefault false
    boolean

    Hover lift (2px and a floating shadow, a tint on ghost cards), a 0.98 press, pointer cursor and the focus ring; media zooms on hover. On by default with onClick, with a CardLink as the title prop, and with asChild onto a link, button or label. With the parts, set it next to a CardLink so the card really goes somewhere.

  • selecteddefault false
    boolean

    A ring in the tone around selectable cards (plans, addresses, payment methods). With onClick the card also reports aria-pressed.

  • disableddefault false
    boolean

    Dims the card and blocks the pointer, the lift and the press. Link and button cards, and a CardLink inside, get aria-disabled, leave the tab order and ignore clicks; disable other controls inside it yourself.

  • orientationdefault "vertical"
    "vertical" | "horizontal"

    horizontal puts the media at the start from 640px up, bleeding to the top, bottom and start edges; phones keep it on top. With parts, wrap the rest in CardContent.

  • divideddefault false
    boolean

    A hairline above the footer, edge to edge (stopping at start media). The default for every CardFooter inside, which can still override it.

  • asChilddefault false
    boolean

    Renders your single child (an <a>, a router Link, a <label> around a radio) as the card, with its look and press. A link card cannot hold buttons; use a CardLink title for that. The demo swaps in a link and drops the like button.

  • children
    ReactNode

    With the simple props, the body (inside CardBody). Without them, the parts: CardMedia, CardHeader, CardBody, CardFooter.

  • action
    ReactNode

    Simple API: a control at the end of the header (a menu, a like, a badge). It stays clickable above a CardLink.

  • media
    ReactNode

    Simple API: an image URL, a <CardMedia> (for aspect, overlays, inset), or any node (a chart, a map), which fills the media slot at its own height.

  • footer
    ReactNode

    Simple API: footer content (end-aligned), or a <CardFooter> for its own align and divided.

  • onClick
    (event: MouseEvent<HTMLDivElement>) => void

    Makes the card a button: role=button, a Tab stop, Enter and Space, interactive on. Not called while disabled. Prefer asChild with a real <a> for navigation.

  • classNames
    Partial<Record<"media" | "content" | "header" | "title" | "description" | "action" | "body" | "footer", string>>

    Extra classes for the parts the simple API renders.

  • className
    string

    Extra classes for the card itself, merged last. Override the spacing vars here, e.g. [--card-padding:12px].

Parts

  • CardMedia

    component

    Photo or custom media that bleeds to the card edges (it reads --card-padding). Its children sit on top of the photo (a badge, a like button; direct child controls stay clickable above a CardLink), or are the media when there is no src.

    • src
      string

      Image URL, drawn with object-cover.

    • altdefault ""
      string

      Alt text; empty marks the photo decorative. Describe it only when it says something the text does not.

    • aspectdefault "16/10"
      "video" | "square" | "4/3" | "16/10" | "auto"

      The box ratio; auto takes the content's own height.

    • position
      "top" | "start"

      Where the media sits; inferred from the card's orientation.

    • insetdefault false
      boolean

      Keeps the card padding around the media and rounds its corners instead of bleeding to the edges.

    • zoomdefault true
      boolean

      Scales the photo up a touch on hover in interactive cards.

    • loadingdefault "lazy"
      "lazy" | "eager"

      The image loading strategy.

    • children
      ReactNode

      Overlays on the photo, or the media itself (a chart, a map) when there is no src.

    • classNames
      Partial<Record<"image", string>>

      Extra classes for the img.

  • CardHeader

    component

    Grid with CardTitle and CardDescription on the start and CardAction at the end, centered on a lone title and top-aligned on two lines. Takes div props.

  • CardTitle

    component

    An h3 (15px semibold at md, 14 / 17px at sm / lg) that takes the tone color on tinted cards. Takes h3 props.

    • asChilddefault false
      boolean

      Renders your child (another heading level) with the title styles.

  • CardDescription

    component

    The muted line under the title; deepens on tinted cards so it keeps 4.5:1. Takes p props.

  • CardAction

    component

    The header's end column for a control; relative z-[2], so it stays clickable above a CardLink. Takes div props.

  • CardBody

    component

    Body text at the card's size (13 / 14 / 15px). Takes div props.

  • CardFooter

    component

    Actions or meta in a row, pinned to the bottom when a grid row stretches the card; its direct buttons and links stay clickable above a CardLink. Takes div props.

    • aligndefault "end"
      "start" | "end" | "between"

      How the footer content is distributed.

    • divided
      boolean

      An edge-to-edge hairline above the footer; defaults to the card's divided.

  • CardContent

    component

    The column next to start media in a horizontal card (the simple API always renders it). Takes div props.

  • CardLink

    component

    A stretched link for the title: its ::after covers the card, so a click anywhere opens it (new tab, middle-click and long-press menus included) while CardAction and the direct controls of CardMedia and CardFooter stay separate (give other controls relative z-[2]). As the title prop it is described by the description prop, so a screen reader reads both. The card shows the focus ring; in a disabled card the link leaves the tab order. Takes a props.

    • asChilddefault false
      boolean

      Renders a router Link (or any anchor component) as the stretched link.

Examples

Variants

elevated on a page, outline for quiet frames, soft as the flat gray tile, ghost for padding only.

Stat cards

onClick makes a card a keyboard button (Enter, Space); selected rings the metric in focus.

Settings with a divided footer

The footer hairline runs edge to edge; Save stays disabled until something changes.

Horizontal link card

Media at the start from 640px up, on top on phones. The title is a CardLink; the phone button stays its own button.

Link cards

A CardLink title stretches over the card: one Tab stop, the ring around the whole card, native new-tab.

Selectable plans

A native radio group: arrow keys move the choice, the selected card takes the brand ring.

Tinted

soft and outline cards take a tone or any color; the title follows and the text keeps its contrast.

Sizes

Padding 16, 20 and 24px (one step less on phones) with the title scaling along.

Dependencies

@radix-ui/react-slottonesui-config

Files

  • components/ui/card.tsx

FAQ

Is the React Card component free?

Yes. The source is free and needs no account: copy it from the Code tab or install it with the CLI.

How do I install Card?

Run npx wingo-ui@latest add card. It also adds the Wingo UI items it builds on (Tones and UIProvider) and the npm package @radix-ui/react-slot. With shadcn, run npx shadcn@latest add https://wingo-ui.com/r/card.json.

See also

BadgeAvatarToneslibSkeletonSeparator

Used in

Listing cardPricing PageProfile PageUsers Admin Page

More React layout components

App ShellAccordionCollapsibleDetail LayoutEntity HeaderPage Header
All 12 React layout components

Articles using this component

  • Codex Frontend Design Skill: Pair It With Real Components

    Building UI with AI agents · Nov 6, 2026 · 10 min read

  • shadcn Tailwind v4 Migration: Step by Step From v3

    Next.js and Tailwind CSS · Nov 6, 2026 · 10 min read

  • Tailwind v4 Nextjs 16 Setup: Config, Fonts and 5 Fixes

    Next.js and Tailwind CSS · Nov 6, 2026 · 9 min read

  • shadcn Vite Setup with Tailwind CSS v4 and React 19

    Next.js and Tailwind CSS · Oct 13, 2026 · 7 min read

PreviousApp ShellNext Collapsible
New

2-bedroom apartment, Park Slope

Brooklyn · 580 sq ft · floor 3 of 4

FurnishedBalconyParking spot
$445,000today, 2:20 PM

Turn on interactive for the hover lift, the press and a card-wide link