Component

Card

A panel — solid, glass or ghost — with optional accent ticks.

stablev0.2.0 Chromium 103 ui-scale safe

Install

Copies the file into components/ds/, with its registry dependencies and npm packages. See Installation for the one-time setup.
bunx shadcn@3 add @fastrp/card

Examples

Solid

Open alone
Sunucu · 01

Los Santos

Ana şehir. Ekonomi, meslekler, çeteler ve polis.

Açık248 / 300 oyuncu
Sunucu · 02

Janti

Yeni şehir. Kendi ekonomisi, kendi kuralları.

BakımdaYakında açılıyor

Glass and ghost

Open alone

Glass

Tint, blur and a rim of light.

Over footage and gradients.

Ghost

A frame and no ground.

Grouping on a surface.

API

<Card />

A panel. Compose it from `CardHeader`, `CardTitle`, `CardDescription`, `CardContent` and `CardFooter`; each section pads itself with `--card-pad`, so a card with only content still breathes.

PropTypeDefaultNotes
ticksboolean—Frame the card's opposite corners in the accent — for the one card that leads.
variant"glass" | "ghost" | "solid"—
<CardEyebrow />Takes the props of what it wraps

The small tracked label above a card's title.

<CardTitle />Takes the props of what it wraps

The display voice, sized for a card.

Dependencies

npm

  • class-variance-authority@^0.7.1

Registry

Source

components/ds/card.tsxShow
import { cva, type VariantProps } from 'class-variance-authority';
import type * as React from 'react';
import { CornerTicks } from '@/components/ds/corner-ticks';
import { cn } from '@/lib/utils';

// @fast-ds [email protected]

const cardVariants = cva('relative flex flex-col text-card-foreground', {
  variants: {
    variant: {
      /** The game panel: translucent, blurred, framed, lit along its top edge. */
      solid: 'panel overflow-hidden',
      /** Over footage or a gradient — lighter than a panel. Solid in the FiveM NUI. */
      glass: 'glass rounded-xl',
      /** No ground of its own: a grouping on an existing surface. */
      ghost: 'rounded-xl border border-foreground/10 bg-transparent',
    },
  },
  defaultVariants: { variant: 'solid' },
});

export type CardProps = React.ComponentProps<'div'> &
  VariantProps<typeof cardVariants> & {
    /** Frame the card's opposite corners in the accent — for the one card that leads. */
    ticks?: boolean;
  };

/**
 * A panel. Compose it from `CardHeader`, `CardTitle`, `CardDescription`, `CardContent` and
 * `CardFooter`; each section pads itself with `--card-pad`, so a card with only content still
 * breathes.
 */
function Card({ className, variant, ticks, children, ...props }: CardProps) {
  return (
    <div data-slot="card" className={cn(cardVariants({ variant }), className)} {...props}>
      {ticks && <CornerTicks tone="primary" corners={['top-left', 'bottom-right']} />}
      {children}
    </div>
  );
}

function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
  return (
    <div
      data-slot="card-header"
      className={cn(
        'flex flex-col gap-1.5 p-[var(--card-pad)] pb-0 last:pb-[var(--card-pad)]',
        className,
      )}
      {...props}
    />
  );
}

/** The display voice, sized for a card. */
function CardTitle({ className, ...props }: React.ComponentProps<'h3'>) {
  return (
    <h3
      data-slot="card-title"
      className={cn('font-display text-3xl leading-none text-foreground', className)}
      {...props}
    />
  );
}

function CardDescription({ className, ...props }: React.ComponentProps<'p'>) {
  return (
    <p
      data-slot="card-description"
      className={cn('text-sm leading-relaxed text-muted-foreground', className)}
      {...props}
    />
  );
}

/** The small tracked label above a card's title. */
function CardEyebrow({ className, ...props }: React.ComponentProps<'span'>) {
  return (
    <span
      data-slot="card-eyebrow"
      className={cn('text-eyebrow uppercase text-muted-foreground', className)}
      {...props}
    />
  );
}

function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
  return (
    <div
      data-slot="card-content"
      className={cn('flex-1 p-[var(--card-pad)]', className)}
      {...props}
    />
  );
}

function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
  return (
    <div
      data-slot="card-footer"
      className={cn(
        'flex items-center gap-3 border-t border-foreground/10 bg-black/15 px-[var(--card-pad)] py-4',
        className,
      )}
      {...props}
    />
  );
}

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