Skip to main content

General

Collapsible code

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

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

@props([
    'open' => false,
    'icon' => null,
    'trigger' => null,
])

@php
    /*
    | Collapsible — a single show/hide region (unlike the grouped accordion).
    | The default trigger is a full-width row with a chevron; pass `open` to
    | start expanded. A plain-text `trigger` (prop or slot) is rendered inside
    | the default styled row; a trigger slot containing markup replaces the
    | row entirely (bring your own padding — `toggle()` and `open` are in scope).
    |
    | Usage:
    |   <x-ui.collapsible trigger="Advanced options">
    |       <p>Hidden settings go here.</p>
    |   </x-ui.collapsible>
    |
    |   <x-ui.collapsible :open="true" icon="gear">
    |       <x-slot:trigger><div class="flex items-center justify-between px-4 py-3">Custom heading</div></x-slot:trigger>
    |       ...
    |   </x-ui.collapsible>
    */
    $triggerHtml = $trigger instanceof \Illuminate\View\ComponentSlot ? trim($trigger->toHtml()) : null;
    $triggerIsCustomMarkup = $triggerHtml !== null && $triggerHtml !== '' && $triggerHtml !== strip_tags($triggerHtml);
    $triggerLabel = is_string($trigger) ? e($trigger) : ($triggerIsCustomMarkup ? null : $triggerHtml);
@endphp

<div
    x-data="{ open: @js((bool) $open), toggle() { this.open = ! this.open; } }"
    {{ $attributes->merge(['class' => 'rounded-xl border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900']) }}
>
    @if ($triggerIsCustomMarkup)
        <div @click="toggle()" :aria-expanded="open" role="button" tabindex="0" @keydown.enter.prevent="toggle()" @keydown.space.prevent="toggle()" class="cursor-pointer">
            {{ $trigger }}
        </div>
    @else
        <button
            type="button"
            @click="toggle()"
            :aria-expanded="open"
            class="flex w-full items-center justify-between gap-4 px-4 py-3 text-left transition hover:bg-gray-50 dark:hover:bg-gray-800/40 cursor-pointer"
        >
            <span class="flex items-center gap-2.5 text-sm font-medium text-gray-900 dark:text-white">
                @if ($icon)<x-ui.icon :name="$icon" size="base" class="text-gray-400 dark:text-gray-500" />@endif
                {!! $triggerLabel !== null && $triggerLabel !== '' ? $triggerLabel : 'Toggle' !!}
            </span>
            <x-ui.icon
                name="caret-down" weight="bold" size="base"
                ::class="open ? 'rotate-180' : ''"
                class="shrink-0 text-gray-400 transition-transform duration-200"
            />
        </button>
    @endif

    <div x-show="open" x-collapse x-cloak>
        <div class="px-4 pb-4 text-sm text-gray-600 dark:text-gray-300">
            {{ $slot }}
        </div>
    </div>
</div>