Skip to main content

Layout primitives

Card code

Copy the implementation or inspect every file that belongs to this component unit.

resources/views/components/ui/card.blade.php

@props([
    'padding' => 'base',
    'hover' => false,
    'href' => null,
])

@php
    /*
    | Generic surface container. Compose with <x-ui.card.header>, <x-ui.card.body>,
    | and <x-ui.card.footer>, or just drop content inside.
    |
    | padding: none, sm, base, lg   (applies only when no sub-sections used)
    | hover:   adds lift + ring on hover (great for clickable cards)
    |
    | Usage:
    |   <x-ui.card>Simple content</x-ui.card>
    |   <x-ui.card hover href="/item">...</x-ui.card>
    */
    $paddings = [
        'none' => '',
        'sm' => 'p-4',
        'base' => 'p-6',
        'lg' => 'p-8',
    ];

    $classes = implode(' ', [
        'bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-2xl shadow-sm min-w-0',
        $paddings[$padding] ?? $paddings['base'],
        $hover ? 'transition duration-200 hover:shadow-md hover:-translate-y-0.5 hover:border-gray-300 dark:hover:border-gray-700' : '',
        $href ? 'block' : '',
    ]);
@endphp

@if ($href)
    <a href="{{ $href }}" {{ $attributes->merge(['class' => $classes]) }}>
        {{ $slot }}
    </a>
@else
    <div {{ $attributes->merge(['class' => $classes]) }}>
        {{ $slot }}
    </div>
@endif

resources/views/components/ui/card/body.blade.php

@props([
    'padding' => 'base',
])

@php
    /* Card content section. padding: none, sm, base, lg */
    $paddings = [
        'none' => '',
        'sm' => 'p-4',
        'base' => 'px-6 py-5',
        'lg' => 'p-8',
    ];
@endphp

<div {{ $attributes->merge(['class' => 'bg-gray-50/50 text-sm text-gray-600 dark:bg-gray-950/30 dark:text-gray-300 '.($paddings[$padding] ?? $paddings['base'])]) }}>
    {{ $slot }}
</div>

resources/views/components/ui/card/footer.blade.php

@php
    /* Card footer section. Typically holds actions aligned to the right. */
@endphp

<div {{ $attributes->merge(['class' => 'flex items-center justify-end gap-3 rounded-b-2xl bg-gray-50/50 px-6 py-4 dark:bg-gray-950/30']) }}>
    {{ $slot }}
</div>

resources/views/components/ui/card/header.blade.php

@props([
    'title' => null,
    'description' => null,
])

@php
    /*
    | Card header section. Pass `title`/`description` props, or use the slot for
    | full control. Use the `actions` slot for buttons aligned to the right.
    |
    | Usage:
    |   <x-ui.card.header title="Team members" description="Manage access" />
    */
@endphp

<div {{ $attributes->merge(['class' => 'flex flex-col gap-4 rounded-t-2xl bg-gray-50/50 px-6 py-5 dark:bg-gray-950/30 sm:flex-row sm:items-start sm:justify-between']) }}>
    <div class="min-w-0">
        @if ($title)
            <h3 class="text-base font-semibold text-gray-900 dark:text-white">{{ $title }}</h3>
        @endif
        @if ($description)
            <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">{{ $description }}</p>
        @endif
        {{ $slot }}
    </div>

    @isset($actions)
        <div class="flex w-full shrink-0 flex-wrap items-center gap-2 sm:w-auto sm:justify-end">{{ $actions }}</div>
    @endisset
</div>