Components Reference
Complete API reference for all form components in the Admin package, including prop documentation, validation rules, authorization integration, and accessibility notes.
Overview
All form components in Core PHP:
- Wrap Flux UI components with additional features
- Support authorization via
canGateandcanResourceprops - Include ARIA accessibility attributes
- Work seamlessly with Livewire
- Follow consistent naming conventions
Input
Text input with various types and authorization support.
Basic Usage
<x-forms.input
id="title"
wire:model="title"
label="Title"
placeholder="Enter title"
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | required | Unique identifier for the input |
label | string | null | Label text displayed above input |
helper | string | null | Helper text displayed below input |
canGate | string | null | Gate/policy ability to check |
canResource | mixed | null | Resource to check ability against |
instantSave | bool | false | Use wire:model.live.debounce.500ms |
type | string | 'text' | Input type (text, email, password, number, etc.) |
placeholder | string | null | Placeholder text |
disabled | bool | false | Disable the input |
readonly | bool | false | Make input read-only |
required | bool | false | Mark as required |
min | number | null | Minimum value (for number inputs) |
max | number | null | Maximum value (for number inputs) |
maxlength | number | null | Maximum character length |
Authorization Example
{{-- Input disabled if user cannot update the post --}}
<x-forms.input
id="title"
wire:model="title"
label="Title"
canGate="update"
:canResource="$post"
/>Type Variants
{{-- Text input --}}
<x-forms.input id="name" label="Name" type="text" />
{{-- Email input --}}
<x-forms.input id="email" label="Email" type="email" />
{{-- Password input --}}
<x-forms.input id="password" label="Password" type="password" />
{{-- Number input --}}
<x-forms.input id="quantity" label="Quantity" type="number" min="1" max="100" />
{{-- Date input --}}
<x-forms.input id="date" label="Date" type="date" />
{{-- URL input --}}
<x-forms.input id="website" label="Website" type="url" />Instant Save Mode
{{-- Saves with 500ms debounce --}}
<x-forms.input
id="slug"
wire:model="slug"
label="Slug"
instantSave
/>Accessibility
The component automatically:
- Associates label with input via
id - Links error messages with
aria-describedby - Sets
aria-invalid="true"when validation fails - Includes helper text in accessible description
Textarea
Multi-line text input with authorization support.
Basic Usage
<x-forms.textarea
id="content"
wire:model="content"
label="Content"
rows="10"
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | required | Unique identifier |
label | string | null | Label text |
helper | string | null | Helper text |
canGate | string | null | Gate/policy ability to check |
canResource | mixed | null | Resource for ability check |
instantSave | bool | false | Use live debounced binding |
rows | number | 3 | Number of visible rows |
placeholder | string | null | Placeholder text |
disabled | bool | false | Disable the textarea |
maxlength | number | null | Maximum character length |
Authorization Example
<x-forms.textarea
id="bio"
wire:model="bio"
label="Biography"
rows="5"
canGate="update"
:canResource="$profile"
/>With Character Limit
<x-forms.textarea
id="description"
wire:model="description"
label="Description"
maxlength="500"
helper="Maximum 500 characters"
/>Select
Dropdown select with authorization support.
Basic Usage
<x-forms.select
id="status"
wire:model="status"
label="Status"
>
<flux:select.option value="draft">Draft</flux:select.option>
<flux:select.option value="published">Published</flux:select.option>
<flux:select.option value="archived">Archived</flux:select.option>
</x-forms.select>Props
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | required | Unique identifier |
label | string | null | Label text |
helper | string | null | Helper text |
canGate | string | null | Gate/policy ability to check |
canResource | mixed | null | Resource for ability check |
instantSave | bool | false | Use live binding |
placeholder | string | null | Placeholder option text |
disabled | bool | false | Disable the select |
multiple | bool | false | Allow multiple selections |
Authorization Example
<x-forms.select
id="category"
wire:model="category_id"
label="Category"
canGate="update"
:canResource="$post"
placeholder="Select a category..."
>
@foreach($categories as $category)
<flux:select.option value="{{ $category->id }}">
{{ $category->name }}
</flux:select.option>
@endforeach
</x-forms.select>With Placeholder
<x-forms.select
id="country"
wire:model="country"
label="Country"
placeholder="Choose a country..."
>
<flux:select.option value="us">United States</flux:select.option>
<flux:select.option value="uk">United Kingdom</flux:select.option>
<flux:select.option value="ca">Canada</flux:select.option>
</x-forms.select>Multiple Selection
<x-forms.select
id="tags"
wire:model="selectedTags"
label="Tags"
multiple
>
@foreach($tags as $tag)
<flux:select.option value="{{ $tag->id }}">
{{ $tag->name }}
</flux:select.option>
@endforeach
</x-forms.select>Checkbox
Single checkbox with authorization support.
Basic Usage
<x-forms.checkbox
id="featured"
wire:model="featured"
label="Featured Post"
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | required | Unique identifier |
label | string | null | Label text (displayed inline) |
helper | string | null | Helper text below checkbox |
canGate | string | null | Gate/policy ability to check |
canResource | mixed | null | Resource for ability check |
instantSave | bool | false | Use live binding |
disabled | bool | false | Disable the checkbox |
value | string | null | Checkbox value (for arrays) |
Authorization Example
<x-forms.checkbox
id="published"
wire:model="published"
label="Publish immediately"
canGate="publish"
:canResource="$post"
/>With Helper Text
<x-forms.checkbox
id="newsletter"
wire:model="newsletter"
label="Subscribe to newsletter"
helper="Receive weekly updates about new features"
/>Checkbox Group
<fieldset>
<legend class="font-medium mb-2">Notifications</legend>
<x-forms.checkbox
id="notify_email"
wire:model="notifications"
label="Email notifications"
value="email"
/>
<x-forms.checkbox
id="notify_sms"
wire:model="notifications"
label="SMS notifications"
value="sms"
/>
<x-forms.checkbox
id="notify_push"
wire:model="notifications"
label="Push notifications"
value="push"
/>
</fieldset>Toggle
Switch-style toggle with authorization support.
Basic Usage
<x-forms.toggle
id="active"
wire:model="active"
label="Active"
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | required | Unique identifier |
label | string | null | Label text (displayed to the left) |
helper | string | null | Helper text below toggle |
canGate | string | null | Gate/policy ability to check |
canResource | mixed | null | Resource for ability check |
instantSave | bool | false | Use live binding |
disabled | bool | false | Disable the toggle |
Authorization Example
<x-forms.toggle
id="is_admin"
wire:model="is_admin"
label="Administrator"
canGate="manageRoles"
:canResource="$user"
/>Instant Save
{{-- Toggle that saves immediately --}}
<x-forms.toggle
id="notifications_enabled"
wire:model="notifications_enabled"
label="Enable Notifications"
instantSave
/>With Helper
<x-forms.toggle
id="two_factor"
wire:model="two_factor_enabled"
label="Two-Factor Authentication"
helper="Add an extra layer of security to your account"
/>Button
Action button with variants and authorization support.
Basic Usage
<x-forms.button type="submit">
Save Changes
</x-forms.button>Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | string | 'primary' | Button style variant |
type | string | 'submit' | Button type (submit, button, reset) |
canGate | string | null | Gate/policy ability to check |
canResource | mixed | null | Resource for ability check |
disabled | bool | false | Disable the button |
loading | bool | false | Show loading state |
Variants
{{-- Primary (default) --}}
<x-forms.button variant="primary">Primary</x-forms.button>
{{-- Secondary --}}
<x-forms.button variant="secondary">Secondary</x-forms.button>
{{-- Danger --}}
<x-forms.button variant="danger">Delete</x-forms.button>
{{-- Ghost --}}
<x-forms.button variant="ghost">Cancel</x-forms.button>Authorization Example
{{-- Button disabled if user cannot delete --}}
<x-forms.button
variant="danger"
canGate="delete"
:canResource="$post"
wire:click="delete"
>
Delete Post
</x-forms.button>With Loading State
<x-forms.button type="submit" wire:loading.attr="disabled">
<span wire:loading.remove>Save</span>
<span wire:loading>Saving...</span>
</x-forms.button>As Link
<x-forms.button
variant="secondary"
type="button"
onclick="window.location.href='{{ route('admin.posts') }}'"
>
Cancel
</x-forms.button>Authorization Props Reference
All form components support authorization through consistent props.
How Authorization Works
When canGate and canResource are provided, the component checks if the authenticated user can perform the specified ability on the resource:
// Equivalent PHP check
auth()->user()?->can($canGate, $canResource)If the check fails, the component is disabled (not hidden).
Props
| Prop | Type | Description |
|---|---|---|
canGate | string | The ability/gate name to check (e.g., 'update', 'delete', 'publish') |
canResource | mixed | The resource to check the ability against (usually a model instance) |
Examples
Basic Policy Check:
<x-forms.input
id="title"
wire:model="title"
canGate="update"
:canResource="$post"
/>Multiple Components with Same Auth:
@php $canEdit = auth()->user()?->can('update', $post); @endphp
<x-forms.input id="title" wire:model="title" :disabled="!$canEdit" />
<x-forms.textarea id="content" wire:model="content" :disabled="!$canEdit" />
<x-forms.button type="submit" :disabled="!$canEdit">Save</x-forms.button>Combining with Blade Directives:
@can('update', $post)
<x-forms.input id="title" wire:model="title" />
<x-forms.button type="submit">Save</x-forms.button>
@else
<p>You do not have permission to edit this post.</p>
@endcanDefining Policies
<?php
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
class PostPolicy
{
public function update(User $user, Post $post): bool
{
return $user->id === $post->author_id
|| $user->hasRole('editor');
}
public function delete(User $user, Post $post): bool
{
return $user->hasRole('admin');
}
public function publish(User $user, Post $post): bool
{
return $user->hasPermission('posts.publish')
&& $post->status === 'draft';
}
}Accessibility Notes
ARIA Attributes
All components automatically include appropriate ARIA attributes:
| Attribute | Usage |
|---|---|
aria-labelledby | Links to label element |
aria-describedby | Links to helper text and error messages |
aria-invalid | Set to true when validation fails |
aria-required | Set when field is required |
aria-disabled | Set when field is disabled |
Label Association
Labels are automatically associated with inputs via the id prop:
<x-forms.input id="email" label="Email Address" />
{{-- Renders as: --}}
<flux:field>
<flux:label for="email">Email Address</flux:label>
<flux:input id="email" name="email" />
</flux:field>Error Announcements
Validation errors are linked to inputs and announced to screen readers:
{{-- Component renders error with aria-describedby link --}}
<flux:error name="email" />
{{-- Screen readers announce: "Email is required" --}}Focus Management
- Tab order follows visual order
- Focus states are clearly visible
- Error focus moves to first invalid field
Keyboard Support
| Component | Keyboard Support |
|---|---|
| Input | Standard text input |
| Textarea | Standard multiline |
| Select | Arrow keys, Enter, Escape |
| Checkbox | Space to toggle |
| Toggle | Space to toggle, Arrow keys |
| Button | Enter/Space to activate |
Validation Integration
Server-Side Validation
Components automatically display Laravel validation errors:
// In Livewire component
protected array $rules = [
'title' => 'required|max:255',
'content' => 'required',
'status' => 'required|in:draft,published',
];
public function save(): void
{
$this->validate();
// Errors automatically shown on components
}Real-Time Validation
public function updated($propertyName): void
{
$this->validateOnly($propertyName);
}{{-- Shows validation error as user types --}}
<x-forms.input
id="email"
wire:model.live="email"
label="Email"
/>Custom Error Messages
protected array $messages = [
'title.required' => 'Please enter a post title.',
'content.required' => 'Post content cannot be empty.',
];Complete Form Example
<form wire:submit="save" class="space-y-6">
{{-- Title --}}
<x-forms.input
id="title"
wire:model="title"
label="Title"
placeholder="Enter post title"
canGate="update"
:canResource="$post"
/>
{{-- Slug with instant save --}}
<x-forms.input
id="slug"
wire:model="slug"
label="Slug"
helper="URL-friendly version of the title"
instantSave
canGate="update"
:canResource="$post"
/>
{{-- Content --}}
<x-forms.textarea
id="content"
wire:model="content"
label="Content"
rows="15"
placeholder="Write your content here..."
canGate="update"
:canResource="$post"
/>
{{-- Category --}}
<x-forms.select
id="category_id"
wire:model="category_id"
label="Category"
placeholder="Select a category..."
canGate="update"
:canResource="$post"
>
@foreach($categories as $category)
<flux:select.option value="{{ $category->id }}">
{{ $category->name }}
</flux:select.option>
@endforeach
</x-forms.select>
{{-- Status --}}
<x-forms.select
id="status"
wire:model="status"
label="Status"
canGate="update"
:canResource="$post"
>
<flux:select.option value="draft">Draft</flux:select.option>
<flux:select.option value="published">Published</flux:select.option>
<flux:select.option value="archived">Archived</flux:select.option>
</x-forms.select>
{{-- Featured toggle --}}
<x-forms.toggle
id="featured"
wire:model="featured"
label="Featured Post"
helper="Display prominently on the homepage"
canGate="update"
:canResource="$post"
/>
{{-- Newsletter checkbox --}}
<x-forms.checkbox
id="notify_subscribers"
wire:model="notify_subscribers"
label="Notify subscribers"
helper="Send email notification when published"
canGate="publish"
:canResource="$post"
/>
{{-- Actions --}}
<div class="flex gap-3 pt-4 border-t">
<x-forms.button
type="submit"
canGate="update"
:canResource="$post"
>
Save Changes
</x-forms.button>
<x-forms.button
variant="secondary"
type="button"
onclick="window.location.href='{{ route('admin.posts') }}'"
>
Cancel
</x-forms.button>
@can('delete', $post)
<x-forms.button
variant="danger"
type="button"
wire:click="delete"
wire:confirm="Are you sure you want to delete this post?"
class="ml-auto"
>
Delete
</x-forms.button>
@endcan
</div>
</form>