Card Components

Container components for organizing content with headers, footers, and skeleton loading states.

Card Components

Card components provide structured containers for organizing content. They support headers, footers, descriptions, and loading skeleton states for a polished user experience.

Available Card Components

Component Purpose
<x-card.card> Main content container with slots
<x-card.card-skeleton> Loading placeholder for cards
<x-dashboard-collapsible-card> Collapsible dashboard card
<x-collapsible-section> Collapsible content section

Card Component

The primary card component with flexible header, body, and footer sections.

Slots

Slot Description
header Card header content
headerRight Right-aligned header content
headerDescription Descriptive text below header
default Main card body content
footer Card footer content

Variables

Variable Type Default Description
$class string '' Additional CSS classes for container
$skeleton boolean false Show skeleton loading state
$headerClass string '' Additional classes for header
$headerTitleClass string '' Classes for header title area
$headerRightClass string '' Classes for right header area
$headerDescriptionClass string '' Classes for description
$bodyClass string '' Additional classes for body
$footerClass string '' Additional classes for footer

Basic Usage

<x-card.card>
    <p>Simple card content goes here.</p>
</x-card.card>

With Header

<x-card.card>
    <x-slot name="header">Card Title</x-slot>

    <p>Card content with a header.</p>
</x-card.card>

With Header and Footer

<x-card.card>
    <x-slot name="header">User Settings</x-slot>

    <div class="space-y-4">
        <x-inputs.input label="Name" name="name" />
        <x-inputs.input label="Email" name="email" type="email" />
    </div>

    <x-slot name="footer">
        <x-buttons.button variant="secondary">Cancel</x-buttons.button>
        <x-buttons.button variant="primary">Save Changes</x-buttons.button>
    </x-slot>
</x-card.card>

With Header Right Content

<x-card.card>
    <x-slot name="header">Recent Orders</x-slot>
    <x-slot name="headerRight">
        <x-buttons.button as="a" href="/orders" variant="secondary" icon="lucide:external-link">
            View All
        </x-buttons.button>
    </x-slot>

    {{-- Orders table --}}
    <table class="w-full">
        ...
    </table>
</x-card.card>

With Header Description

<x-card.card>
    <x-slot name="header">API Settings</x-slot>
    <x-slot name="headerDescription">
        Configure your API keys and webhook endpoints.
    </x-slot>

    <div class="space-y-4">
        <x-inputs.input
            label="API Key"
            name="api_key"
            :value="$apiKey"
            disabled
        />
    </div>
</x-card.card>

With Loading Skeleton

{{-- Shows skeleton while loading --}}
<x-card.card :skeleton="$isLoading">
    <x-slot name="header">User Profile</x-slot>

    @if(!$isLoading)
        <p>{{ $user->name }}</p>
        <p>{{ $user->email }}</p>
    @endif
</x-card.card>

Custom Classes

<x-card.card
    class="bg-primary/5"
    headerClass="bg-primary text-white"
    bodyClass="p-8"
    footerClass="justify-end"
>
    <x-slot name="header">Custom Styled Card</x-slot>

    <p>Content with custom styling.</p>

    <x-slot name="footer">
        <x-buttons.button variant="primary">Action</x-buttons.button>
    </x-slot>
</x-card.card>

Real Examples from Codebase

{{-- Settings page card --}}
<x-card.card>
    <x-slot name="header">{{ __('General Settings') }}</x-slot>
    <x-slot name="headerDescription">
        {{ __('Configure your application settings.') }}
    </x-slot>

    <form wire:submit="save">
        <div class="space-y-4">
            <x-inputs.input
                label="{{ __('Site Name') }}"
                name="site_name"
                wire:model="site_name"
            />

            <x-inputs.textarea
                label="{{ __('Site Description') }}"
                name="site_description"
                wire:model="site_description"
            />
        </div>

        <x-slot name="footer">
            <x-buttons.button type="submit" variant="primary" loadingTarget="save">
                {{ __('Save Settings') }}
            </x-buttons.button>
        </x-slot>
    </form>
</x-card.card>

{{-- User profile card --}}
<x-card.card>
    <x-slot name="header">{{ __('Profile Information') }}</x-slot>
    <x-slot name="headerRight">
        <span class="text-sm text-gray-500">
            {{ __('Last updated') }}: {{ $user->updated_at->diffForHumans() }}
        </span>
    </x-slot>

    <div class="flex items-center gap-4">
        <img src="{{ $user->avatar_url }}" class="w-16 h-16 rounded-full" />
        <div>
            <h3 class="font-medium">{{ $user->name }}</h3>
            <p class="text-sm text-gray-500">{{ $user->email }}</p>
        </div>
    </div>
</x-card.card>

Card Skeleton Component

Loading placeholder that mimics card content while data loads.

Basic Usage

{{-- Standalone skeleton --}}
<x-card.card-skeleton />

In Card Context

The card component automatically shows the skeleton when skeleton is true:

<x-card.card :skeleton="!$dataLoaded">
    {{-- Content appears after loading --}}
</x-card.card>

Custom Skeleton Layout

<div class="rounded-md border border-gray-200 dark:border-gray-800 p-4">
    <div class="animate-pulse space-y-4">
        {{-- Header skeleton --}}
        <div class="h-4 bg-gray-200 dark:bg-gray-700 rounded w-1/3"></div>

        {{-- Content lines --}}
        <div class="space-y-2">
            <div class="h-3 bg-gray-200 dark:bg-gray-700 rounded w-full"></div>
            <div class="h-3 bg-gray-200 dark:bg-gray-700 rounded w-5/6"></div>
            <div class="h-3 bg-gray-200 dark:bg-gray-700 rounded w-4/6"></div>
        </div>
    </div>
</div>

Dashboard Collapsible Card

Specialized card for dashboard widgets that can be collapsed/expanded.

Props

Prop Type Default Description
title string required Card title
collapsed boolean false Initial collapsed state
icon string null Header icon

Basic Usage

<x-dashboard-collapsible-card title="Recent Activity">
    <ul class="space-y-2">
        @foreach($activities as $activity)
            <li>{{ $activity->description }}</li>
        @endforeach
    </ul>
</x-dashboard-collapsible-card>

Initially Collapsed

<x-dashboard-collapsible-card
    title="Advanced Options"
    :collapsed="true"
    icon="lucide:settings"
>
    <p>Advanced configuration options...</p>
</x-dashboard-collapsible-card>

Collapsible Section

A general-purpose collapsible content section.

Props

Prop Type Default Description
title string required Section title
open boolean false Initial open state
icon string null Title icon

Basic Usage

<x-collapsible-section title="Additional Information">
    <p>This content can be collapsed and expanded.</p>
</x-collapsible-section>

Initially Open

<x-collapsible-section title="FAQ" :open="true">
    <div class="space-y-4">
        <div>
            <h4 class="font-medium">Question 1?</h4>
            <p class="text-gray-600">Answer 1.</p>
        </div>
        <div>
            <h4 class="font-medium">Question 2?</h4>
            <p class="text-gray-600">Answer 2.</p>
        </div>
    </div>
</x-collapsible-section>

Multiple Sections

<div class="space-y-4">
    <x-collapsible-section title="Personal Information" :open="true">
        <x-inputs.input label="Name" name="name" />
        <x-inputs.input label="Email" name="email" />
    </x-collapsible-section>

    <x-collapsible-section title="Address">
        <x-inputs.input label="Street" name="street" />
        <x-inputs.input label="City" name="city" />
    </x-collapsible-section>

    <x-collapsible-section title="Preferences">
        <x-inputs.checkbox label="Newsletter" name="newsletter" />
    </x-collapsible-section>
</div>

Card Layouts

Grid of Cards

<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
    <x-card.card>
        <x-slot name="header">Card 1</x-slot>
        <p>Content for card 1.</p>
    </x-card.card>

    <x-card.card>
        <x-slot name="header">Card 2</x-slot>
        <p>Content for card 2.</p>
    </x-card.card>

    <x-card.card>
        <x-slot name="header">Card 3</x-slot>
        <p>Content for card 3.</p>
    </x-card.card>
</div>

Stacked Cards

<div class="space-y-6">
    <x-card.card>
        <x-slot name="header">Section 1</x-slot>
        <p>First section content.</p>
    </x-card.card>

    <x-card.card>
        <x-slot name="header">Section 2</x-slot>
        <p>Second section content.</p>
    </x-card.card>
</div>

Card with Stats

<x-card.card>
    <x-slot name="header">Statistics</x-slot>

    <div class="grid grid-cols-3 gap-4 text-center">
        <div>
            <p class="text-3xl font-bold text-primary">{{ $totalUsers }}</p>
            <p class="text-sm text-gray-500">{{ __('Total Users') }}</p>
        </div>
        <div>
            <p class="text-3xl font-bold text-success">{{ $activeUsers }}</p>
            <p class="text-sm text-gray-500">{{ __('Active') }}</p>
        </div>
        <div>
            <p class="text-3xl font-bold text-warning">{{ $pendingUsers }}</p>
            <p class="text-sm text-gray-500">{{ __('Pending') }}</p>
        </div>
    </div>
</x-card.card>

Best Practices

  1. Use headers for context - Always include a header for non-trivial cards
  2. Group related actions in footer - Place buttons and actions in the footer slot
  3. Show loading states - Use skeleton when fetching data
  4. Keep cards focused - One card should serve one purpose
  5. Use consistent spacing - Apply space-y-4 or similar for internal content
  6. Consider collapsible for long content - Use collapsible cards for optional/advanced sections

Next Steps

  • Inputs - Form inputs to use within cards
  • Buttons - Action buttons for card footers
  • Modals - Dialog overlays
/