php-framework/docs/packages/admin/components-reference.md

18 KiB

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

<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>
<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>
@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

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>

Learn More