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 canGate and canResource props
- Include ARIA accessibility attributes
- Work seamlessly with Livewire
- Follow consistent naming conventions
Input¶
Text input with various types and authorization support.
Basic Usage¶
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¶
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¶
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¶
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¶
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:
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:
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>
@endcan
Defining 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¶
{{-- 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>