---
title: Card
description: A container that groups related content and actions.
---

<ComponentPreview name="card-demo" />

## Installation

<Tabs defaultValue="cli">

<TabsList>
  <TabsTrigger value="cli">CLI</TabsTrigger>
  <TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">

```bash
npx lightswind@latest add card
```

</TabsContent>

<TabsContent value="manual">

<Steps>

<Step>Copy and paste the following code into your project.</Step>

```tsx

import * as React from "react";
import { cn } from "@/components/lib/utils";

interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
  /** Makes the card have a hover effect */
  hoverable?: boolean;
  /** Makes the card have a bordered appearance */
  bordered?: boolean;
  /** Renders the card with compact padding */
  compact?: boolean;
}

const Card = React.forwardRef<
  HTMLDivElement,
  CardProps
>(({ className, hoverable = false, bordered = false, compact = false, ...props }, ref) => (
  <div
    ref={ref}
    className={cn(
      "rounded-2xl bg-white/80 dark:bg-zinc-900/60 text-card-foreground backdrop-blur-md border border-zinc-200/80 dark:border-zinc-800/80 shadow-xs transition-all duration-300",
      bordered && "border border-zinc-200/80 dark:border-zinc-800/80",
      hoverable ? "hover:shadow-xl hover:shadow-primarylw/5 hover:border-zinc-300 dark:hover:border-zinc-700/80 hover:-translate-y-0.5" : "",
      compact ? "p-3 sm:p-4" : "p-0",
      className
    )}
    {...props}
  />
));
Card.displayName = "Card";

interface CardHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
  /** Adjusts the spacing in the header */
  spacing?: "default" | "compact" | "relaxed";
}

const CardHeader = React.forwardRef<
  HTMLDivElement,
  CardHeaderProps
>(({ className, spacing = "default", ...props }, ref) => {
  const spacingClasses = {
    compact: "flex flex-col space-y-1 p-4",
    default: "flex flex-col space-y-1.5 p-6",
    relaxed: "flex flex-col space-y-2 p-8",
  };

  return (
    <div
      ref={ref}
      className={cn(spacingClasses[spacing], className)}
      {...props}
    />
  );
});
CardHeader.displayName = "CardHeader";

interface CardTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {
  /** HTML heading level to use */
  as?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
  /** Adjusts the text size */
  size?: "sm" | "default" | "lg";
}

const CardTitle = React.forwardRef<
  HTMLParagraphElement,
  CardTitleProps
>(({ className, as = "h3", size = "default", ...props }, ref) => {
  const Component = as;
  const sizeClasses = {
    sm: "text-lg",
    default: "text-2xl",
    lg: "text-3xl"
  };

  return (
    <Component
      ref={ref}
      className={cn(
        "font-semibold leading-none tracking-tight",
        sizeClasses[size],
        className
      )}
      {...props}
    />
  );
});
CardTitle.displayName = "CardTitle";

interface CardDescriptionProps extends React.HTMLAttributes<HTMLParagraphElement> {
  /** Makes text smaller or larger */
  size?: "xs" | "sm" | "default";
}

const CardDescription = React.forwardRef<
  HTMLParagraphElement,
  CardDescriptionProps
>(({ className, size = "default", ...props }, ref) => {
  const sizeClasses = {
    xs: "text-xs",
    sm: "text-sm",
    default: "text-sm"
  };

  return (
    <p
      ref={ref}
      className={cn(
        "text-muted-foreground",
        sizeClasses[size],
        className
      )}
      {...props}
    />
  );
});
CardDescription.displayName = "CardDescription";

interface CardContentProps extends React.HTMLAttributes<HTMLDivElement> {
  /** Removes the top padding when used after CardHeader */
  removeTopPadding?: boolean;
  /** Adjusts content padding */
  padding?: "none" | "sm" | "default" | "lg";
}

const CardContent = React.forwardRef<
  HTMLDivElement,
  CardContentProps
>(({ className, removeTopPadding = true, padding = "default", ...props }, ref) => {
  const paddingClasses = {
    none: "p-0",
    sm: "px-4 py-3",
    default: "p-6",
    lg: "p-8"
  };

  return (
    <div 
      ref={ref} 
      className={cn(
        paddingClasses[padding], 
        removeTopPadding && padding !== "none" ? "pt-0" : "",
        className
      )} 
      {...props}
    />
  );
});
CardContent.displayName = "CardContent";

interface CardFooterProps extends React.HTMLAttributes<HTMLDivElement> {
  /** Changes the alignment of footer items */
  align?: "start" | "center" | "end" | "between" | "around";
  /** Changes the direction of footer items */
  direction?: "row" | "column";
}

const CardFooter = React.forwardRef<
  HTMLDivElement,
  CardFooterProps
>(({ className, align = "center", direction = "row", ...props }, ref) => {
  const alignClasses = {
    start: "justify-start",
    center: "justify-center",
    end: "justify-end",
    between: "justify-between",
    around: "justify-around"
  };

  const directionClasses = {
    row: "flex-row",
    column: "flex-col"
  };

  return (
    <div
      ref={ref}
      className={cn(
        "flex items-center p-6 pt-0",
        alignClasses[align],
        directionClasses[direction],
        className
      )}
      {...props}
    />
  );
});
CardFooter.displayName = "CardFooter";

export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };

```

</Steps>

</TabsContent>

</Tabs>

## Usage

```tsx
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@/components/lightswind/card"
```

```tsx
import {
  Card,
  CardHeader,
  CardTitle,
  CardDescription,
  CardContent,
  CardFooter,
} from "@/components/lightswind/card";
import { Button } from "@/components/lightswind/button";

export function CardDemo() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Create project</CardTitle>
        <CardDescription>Deploy your new project in one-click.</CardDescription>
      </CardHeader>
      <CardContent>
        <p>Card content goes here.</p>
      </CardContent>
      <CardFooter>
        <Button>Deploy</Button>
      </CardFooter>
    </Card>
  );
}
```
