# Field

Combine labels, controls, and help text to compose accessible form fields.

- Install: `php artisan blatui:add field`
- Source: https://blatui.remix-it.com/r/field.json
- Composer: `composer require gehrisandro/tailwind-merge-laravel`

## resources/views/components/ui/field.blade.php

```blade
@props(['orientation' => 'vertical'])

@php
    $orientations = [
        'vertical' => 'flex-col [&>*]:w-full [&>.sr-only]:w-auto',
        'horizontal' => 'flex-row items-center [&>[data-slot=field-label]]:flex-auto has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=switch]]:mt-px',
        'responsive' => 'flex-col [&>*]:w-full @md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto',
    ];
@endphp

<div
    role="group"
    data-slot="field"
    data-orientation="{{ $orientation }}"
    x-data="{}"
    x-blat-field
    {{ $attributes->twMerge('group/field flex w-full gap-2 data-[invalid=true]:text-destructive '.($orientations[$orientation] ?? $orientations['vertical'])) }}
>
    {{ $slot }}
</div>
```

## resources/views/components/ui/field-content.blade.php

```blade
<div data-slot="field-content" {{ $attributes->twMerge('group/field-content flex flex-1 flex-col gap-1.5 leading-snug') }}>
    {{ $slot }}
</div>
```

## resources/views/components/ui/field-description.blade.php

```blade
<p data-slot="field-description" {{ $attributes->twMerge('text-muted-foreground text-sm leading-normal font-normal group-has-[[data-orientation=horizontal]]/field:text-balance') }}>{{ $slot }}</p>
```

## resources/views/components/ui/field-error.blade.php

```blade
@props([
    'messages' => null,
])

@php
    // Mirrors shadcn's <FieldError errors={[...]} />: accepts slot content, a single
    // string, or an array of messages / { message } objects. One message renders as
    // text; several render as a bulleted list. Nothing renders when there's no content.
    $items = collect(is_array($messages) ? $messages : ($messages !== null && $messages !== '' ? [$messages] : []))
        ->map(fn ($m) => is_array($m) ? ($m['message'] ?? null) : $m)
        ->filter(fn ($m) => filled($m))
        ->unique()
        ->values();
    $hasSlot = trim($slot) !== '';
@endphp

@if ($hasSlot || $items->isNotEmpty())
    <div role="alert" data-slot="field-error" {{ $attributes->twMerge('text-destructive text-sm font-normal') }}>
        @if ($hasSlot)
            {{ $slot }}
        @elseif ($items->count() === 1)
            {{ $items->first() }}
        @else
            <ul class="ml-4 flex list-disc flex-col gap-1">
                @foreach ($items as $message)
                    <li>{{ $message }}</li>
                @endforeach
            </ul>
        @endif
    </div>
@endif
```

## resources/views/components/ui/field-group.blade.php

```blade
<div data-slot="field-group" {{ $attributes->twMerge('group/field-group @container/field-group flex w-full flex-col gap-7 data-[slot=checkbox-group]:gap-3') }}>
    {{ $slot }}
</div>
```

## resources/views/components/ui/field-label.blade.php

```blade
@props(['for' => null])

<label
    @if ($for) for="{{ $for }}" @endif
    data-slot="field-label"
    {{ $attributes->twMerge('group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50 has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col has-[>[data-slot=field]]:rounded-md text-sm leading-snug font-medium select-none') }}
>{{ $slot }}</label>
```

## resources/views/components/ui/field-legend.blade.php

```blade
@props(['variant' => 'legend'])

<legend
    data-slot="field-legend"
    data-variant="{{ $variant }}"
    {{ $attributes->twMerge('mb-3 font-medium data-[variant=legend]:text-base data-[variant=label]:text-sm') }}
>{{ $slot }}</legend>
```

## resources/views/components/ui/field-separator.blade.php

```blade
<div
    data-slot="field-separator"
    {{ $attributes->twMerge('relative -my-2 h-5 text-sm') }}
>
    <div class="bg-border absolute inset-0 top-1/2 h-px"></div>
    @if (trim($slot) !== '')
        <span class="bg-background text-muted-foreground relative mx-auto block w-fit px-2">{{ $slot }}</span>
    @endif
</div>
```

## resources/views/components/ui/field-set.blade.php

```blade
<fieldset data-slot="field-set" {{ $attributes->twMerge('flex flex-col gap-6 has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3') }}>
    {{ $slot }}
</fieldset>
```

## resources/views/components/ui/field-title.blade.php

```blade
<div data-slot="field-title" {{ $attributes->twMerge('flex w-fit items-center gap-2 text-sm leading-snug font-medium') }}>{{ $slot }}</div>
```
