Displays a card with header, content, and footer.

Default Size
Default Card
This card uses the default size variant.

The card component supports a size prop that defaults to "default" for standard spacing and sizing.

Small Size
Small Card
This card uses the small size variant.

The card component supports a size prop that can be set to "sm" for a more compact appearance.

Content Edge to Edge
Terms of Service
Review the terms before accepting the agreement.

These terms govern your use of the workspace, including access to shared documents, project files, and collaboration tools.

You are responsible for the content you upload and for ensuring that your team has the appropriate permissions to view or edit it.

We may update features or limits as the service evolves. When those changes materially affect your workflow, we will notify your workspace administrators.

By continuing, you agree to keep your account credentials secure and to follow your organization's acceptable use policies.

Custom Spacing
Release Health
Track readiness across launch signals.
Checks passed 24 / 26
Open blockers 2
Header with Border
Header with Border
This is a card with a header that has a bottom border.

The header has a border-b class applied, creating a visual separation between the header and content sections.

Footer with Border

The footer has a border-t class applied, creating a visual separation between the content and footer sections.

Header with Border (Small)
Header with Border
This is a small card with a header that has a bottom border.

The header has a border-b class applied, creating a visual separation between the header and content sections.

Footer with Border (Small)

The footer has a border-t class applied, creating a visual separation between the content and footer sections.

With Image
Beautiful Landscape
A stunning view that captures the essence of natural beauty.
With Image (Small)
Beautiful Landscape
A stunning view that captures the essence of natural beauty.
Login
Login to your account
Enter your email below to login to your account
Meeting Notes
Meeting Notes
Transcript from the meeting with the client.

Client requested dashboard redesign with focus on mobile responsiveness.

  1. New analytics widgets for daily/weekly metrics
  2. Simplified navigation menu
  3. Dark mode support
  4. Timeline: 6 weeks
  5. Follow-up meeting scheduled for next Tuesday

Installation

Install the dependencies

pnpm add cn class-variance-authority

Copy the component

Copy the following files into src/lib/components/ui/card.

src/lib/components/ui/card/Card.svelte
<script lang="ts">
  import type { CardProps } from './types.js';
  import { cn } from 'cn';
  let { children, class: classProp, size = 'default', ...props }: CardProps = $props();
</script>
<div data-slot="card" data-size={size} {...props} class={cn('ring-foreground/10 bg-card text-card-foreground gap-(--card-spacing) overflow-hidden rounded-xl py-(--card-spacing) text-sm ring-1 [--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 group/card flex flex-col', classProp)}>
  {@render children?.()}
</div>
src/lib/components/ui/card/CardAction.svelte
<script lang="ts">
  import type { CardActionProps } from './types.js';
  import { cn } from 'cn';
  let { children, class: classProp, ...props }: CardActionProps = $props();
</script>
<div data-slot="card-action" {...props} class={cn('col-start-2 row-span-2 row-start-1 self-start justify-self-end', classProp)}>
  {@render children?.()}
</div>
src/lib/components/ui/card/CardContent.svelte
<script lang="ts">
  import type { CardContentProps } from './types.js';
  import { cn } from 'cn';
  let { children, class: classProp, ...props }: CardContentProps = $props();
</script>
<div data-slot="card-content" {...props} class={cn('px-(--card-spacing)', classProp)}>
  {@render children?.()}
</div>
src/lib/components/ui/card/CardDescription.svelte
<script lang="ts">
  import type { CardDescriptionProps } from './types.js';
  import { cn } from 'cn';
  let { children, class: classProp, ...props }: CardDescriptionProps = $props();
</script>
<div data-slot="card-description" {...props} class={cn('text-muted-foreground text-sm', classProp)}>
  {@render children?.()}
</div>
src/lib/components/ui/card/CardFooter.svelte
<script lang="ts">
  import type { CardFooterProps } from './types.js';
  import { cn } from 'cn';
  let { children, class: classProp, ...props }: CardFooterProps = $props();
</script>
<div data-slot="card-footer" {...props} class={cn('bg-muted/50 rounded-b-xl border-t p-(--card-spacing) flex items-center', classProp)}>
  {@render children?.()}
</div>
src/lib/components/ui/card/CardHeader.svelte
<script lang="ts">
  import type { CardHeaderProps } from './types.js';
  import { cn } from 'cn';
  let { children, class: classProp, ...props }: CardHeaderProps = $props();
</script>
<div data-slot="card-header" {...props} class={cn('gap-1 rounded-t-xl px-(--card-spacing) [.border-b]:pb-(--card-spacing) group/card-header @container/card-header grid auto-rows-min items-start has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto]', classProp)}>
  {@render children?.()}
</div>
src/lib/components/ui/card/CardTitle.svelte
<script lang="ts">
  import type { CardTitleProps } from './types.js';
  import { cn } from 'cn';
  let { children, class: classProp, ...props }: CardTitleProps = $props();
</script>
<div data-slot="card-title" {...props} class={cn('text-base leading-snug font-medium group-data-[size=sm]/card:text-sm', classProp)}>
  {@render children?.()}
</div>
src/lib/components/ui/card/types.ts
import type { HTMLAttributes } from 'svelte/elements';

type NativeCardProps = HTMLAttributes<HTMLDivElement>;

export type CardProps = NativeCardProps & { size?: 'default' | 'sm' };
export type CardHeaderProps = NativeCardProps;
export type CardTitleProps = NativeCardProps;
export type CardDescriptionProps = NativeCardProps;
export type CardActionProps = NativeCardProps;
export type CardContentProps = NativeCardProps;
export type CardFooterProps = NativeCardProps;
src/lib/components/ui/card/index.ts
export { default as Card } from './Card.svelte';
export { default as CardHeader } from './CardHeader.svelte';
export { default as CardTitle } from './CardTitle.svelte';
export { default as CardDescription } from './CardDescription.svelte';
export { default as CardAction } from './CardAction.svelte';
export { default as CardContent } from './CardContent.svelte';
export { default as CardFooter } from './CardFooter.svelte';
export type { CardProps, CardHeaderProps, CardTitleProps, CardDescriptionProps, CardActionProps, CardContentProps, CardFooterProps } from './types.js';

Update the import paths

Change the imports to match your project setup.

Usage

<script lang="ts">
  import { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '$lib/components/ui/card';
</script>
<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>

Image card

Place an image above CardHeader and drop the top padding with pt-0. Put a Badge or an action next to the footer content with ml-auto. Here the footer opens an AlertDialog.

Card
Photo by mymind on Unsplash
Observability Plus is replacing Monitoring
Switch to the improved way to explore your data, with natural language. Monitoring will no longer be available on the Pro plan in November, 2025
Form
User Information
Please fill in your details below