Form
Accessible, composable Blade components for building forms. All components live under the x-pajak-form namespace. Labels, hints, and validation messages are built into each component via props.
Form
A <form> wrapper that handles CSRF injection, method spoofing (PUT, PATCH, DELETE), and renders a translatable submit button automatically. Supports three layout modes via the :layout prop: Stacked (default), Inline (label beside field), and Sectioned (two-column sections with x-pajak-form::section).
<x-pajak-form::form action="#"> <x-pajak-form::email name="demo-email" label="Email" placeholder="[email protected]" /> <x-pajak-form::password name="demo-password" placeholder="Password" /> </x-pajak-form::form>
@use('Pajak\Ui\Common\Enums\Size')
<x-pajak-form::form action="#" submit-text="Subscribe" :submit-size="Size::Lg">
<x-pajak-form::email name="demo-sub-email" label="Email" placeholder="[email protected]" />
</x-pajak-form::form>
@use('Pajak\Ui\Common\Enums\Method')
<x-pajak-form::form action="#" :method="Method::Put" submit-text="Save changes">
<x-pajak-form::input name="fm-name" label="Name" value="John Doe" />
</x-pajak-form::form>
@use('Pajak\Ui\Common\Enums\Method')
@use('Pajak\Ui\Common\Enums\Size')
<x-pajak-form::form
action="#"
:method="Method::Delete"
submit-text="Delete account"
:submit-size="Size::Sm"
>
</x-pajak-form::form>
@use('Pajak\Ui\Form\Enums\FormLayout')
<x-pajak-form::form action="#" :layout="FormLayout::Inline">
<x-pajak-form::input name="description" label="Description" placeholder="Item description" />
<x-pajak-form::select name="category" label="Category" :options="['travel' => 'Travel', 'office' => 'Office', 'software' => 'Software']" />
<x-pajak-form::input name="amount" label="Amount" placeholder="0.00" />
</x-pajak-form::form>
@use('Pajak\Ui\Form\Enums\FormLayout')
<x-pajak-form::form action="#" :layout="FormLayout::Sectioned">
<x-pajak-form::section title="Account" description="How you sign in and how we reach you.">
<x-pajak-form::input name="display_name" label="Display name" placeholder="John Doe" />
<x-pajak-form::email name="email" label="Email" placeholder="[email protected]" />
</x-pajak-form::section>
<x-pajak-form::section title="Notifications" description="Choose what you want to hear about.">
<x-pajak-form::toggle name="filing_reminders" label="Filing reminders" checked />
<x-pajak-form::toggle name="product_news" label="Product news" />
</x-pajak-form::section>
</x-pajak-form::form>
<x-pajak-form::form action="/playground/async" redirect="/"> <x-pajak-form::email name="email" label="Email" placeholder="[email protected]" /> </x-pajak-form::form>
<x-pajak-form::form action="/playground/async" id="demo-async-form"> <x-pajak-form::email name="email" label="Email" placeholder="[email protected]" /> </x-pajak-form::form> <script type="module"> const form = document.getElementById('demo-async-form'); form.addEventListener('pajak:form:success', (e) => { console.log('Success:', e.detail.response); }); form.addEventListener('pajak:form:error', (e) => { console.log('Error:', e.detail.status, e.detail.response); }); form.addEventListener('pajak:form:before-submit', (e) => { // mutate FormData or cancel with e.preventDefault() e.detail.data.set('source', 'demo'); }); </script>
<x-pajak-form::form action="/playground/async" id="demo-extra-data-form"> <x-pajak-form::email name="email" label="Email" placeholder="[email protected]" /> </x-pajak-form::form> <script type="module"> const { PajakForm } = window.Pajak; const form = document.getElementById('demo-extra-data-form'); PajakForm.addData(form, 'locale', 'sk'); PajakForm.addData(form, 'source', 'sidebar'); </script>
Group
A layout wrapper for form fields. Stacks fields vertically with consistent spacing by default. Add :inline="true" to place fields side by side in equal-width columns. Use it when grouping fields outside of a <x-pajak-form::form> - for example, inside a modal or sidebar panel.
<x-pajak-form::group> <x-pajak-form::input name="first_name" label="First name" placeholder="John" /> <x-pajak-form::input name="last_name" label="Last name" placeholder="Doe" /> <x-pajak-form::email name="email" label="Email" placeholder="[email protected]" /> </x-pajak-form::group>
<x-pajak-form::group :inline="true"> <x-pajak-form::input name="first_name" label="First name" placeholder="John" /> <x-pajak-form::input name="last_name" label="Last name" placeholder="Doe" /> <x-pajak-form::select name="title" label="Title" :options="['mr' => 'Mr.', 'ms' => 'Ms.', 'dr' => 'Dr.']" /> </x-pajak-form::group>
<x-pajak-form::group> <x-pajak-form::input name="company" label="Company" placeholder="Acme Inc." /> <x-pajak-form::select name="role" label="Role" :options="['admin' => 'Admin', 'editor' => 'Editor', 'viewer' => 'Viewer']" /> <x-pajak-form::toggle name="active" label="Active account" /> </x-pajak-form::group>
Section
A two-column section divider for use inside a FormLayout::Sectioned form. The left column holds a title and optional description; the right column is the field body slot. Sections are separated by a horizontal border automatically. Can also be used standalone outside a form.
@use('Pajak\Ui\Form\Enums\FormLayout')
<x-pajak-form::form action="#" :layout="FormLayout::Sectioned">
<x-pajak-form::section title="Account" description="How you sign in and how we reach you.">
<x-pajak-form::input name="display_name" label="Display name" placeholder="John Doe" />
<x-pajak-form::email name="email" label="Email" placeholder="[email protected]" />
</x-pajak-form::section>
<x-pajak-form::section title="Notifications" description="Choose what you want to hear about.">
<x-pajak-form::toggle name="filing_reminders" label="Filing reminders" checked />
<x-pajak-form::toggle name="product_news" label="Product news" />
</x-pajak-form::section>
</x-pajak-form::form>
<x-pajak-form::section title="Preferences" description="Adjust your default settings."> <x-pajak-form::select name="language" label="Language" :options="['en' => 'English', 'sk' => 'Slovak', 'cs' => 'Czech']" /> <x-pajak-form::toggle name="dark_mode" label="Dark mode" /> </x-pajak-form::section>
Input
A single-line text field. Supports all HTML input types, three sizes, three states, and an optional leading icon slot.
@use('Pajak\Ui\Common\Enums\Size')
<x-pajak-form::input name="input-sm" :size="Size::Sm" placeholder="Small (sm)" />
<x-pajak-form::input name="input-md" :size="Size::Md" placeholder="Medium (md) - default" />
<x-pajak-form::input name="input-lg" :size="Size::Lg" placeholder="Large (lg)" />
@use('Pajak\Ui\Common\Enums\State')
<x-pajak-form::input name="input-default" placeholder="Default" />
<x-pajak-form::input name="input-error" :state="State::Error" placeholder="Error state" />
<x-pajak-form::input name="input-success" :state="State::Success" placeholder="Success state" />
<x-pajak-form::input name="input-disabled" placeholder="Disabled" :disabled="true" />
<x-pajak-form::input name="input-icon" placeholder="Search…"> <x-slot:icon> <x-heroicon-o-magnifying-glass width="16" height="16" /> </x-slot:icon> </x-pajak-form::input>
<x-pajak-form::input name="username" value="john_doe" />
<x-pajak-form::input name="email-inline" type="email" value="not-an-email" error="Please enter a valid email address." />
A convenience wrapper around x-pajak-form::input with type="email". Accepts all the same props as Input. Defaults autocomplete to 'email'.
<x-pajak-form::email name="email-default" placeholder="[email protected]" />
@use('Pajak\Ui\Common\Enums\State')
<x-pajak-form::email name="email-filled" value="[email protected]" />
<x-pajak-form::email name="email-err" placeholder="[email protected]" :state="State::Error" />
<x-pajak-form::email name="email-ok" value="[email protected]" :state="State::Success" />
<x-pajak-form::email name="email-dis" value="[email protected]" :disabled="true" />
Password
A password input with a visibility toggle. Pass :confirmation="true" to render an inline confirmation field below it.
<x-pajak-form::password name="pw-default" placeholder="Enter password" />
<x-pajak-form::password name="pw-toggle" placeholder="Enter password" :with-toggle="true" />
<x-pajak-form::password name="pw-confirm" placeholder="Enter password" :confirmation="true" confirmation-placeholder="Confirm password" > <x-slot:icon> <x-heroicon-o-lock-closed width="16" height="16" /> </x-slot:icon> <x-slot:confirmation-icon> <x-heroicon-o-lock-open width="16" height="16" /> </x-slot:confirmation-icon> </x-pajak-form::password>
<x-pajak-form::password name="pw-toggle-confirm" placeholder="Enter password" :with-toggle="true" :confirmation="true" confirmation-placeholder="Confirm password" > <x-slot:icon> <x-heroicon-o-lock-closed width="16" height="16" /> </x-slot:icon> <x-slot:confirmation-icon> <x-heroicon-o-lock-open width="16" height="16" /> </x-slot:confirmation-icon> </x-pajak-form::password>
<x-pajak-form::password name="pw-err" placeholder="Enter password" error="Password must be at least 8 characters." />
<x-pajak-form::password name="pw-conf-err" placeholder="Enter password" :confirmation="true" confirmation-placeholder="Confirm password" confirmation-error="Passwords do not match." />
@use('Pajak\Ui\Common\Enums\Size')
<x-pajak-form::password name="pw-sm" :size="Size::Sm" placeholder="Small" />
<x-pajak-form::password name="pw-md" placeholder="Medium (default)" />
<x-pajak-form::password name="pw-lg" :size="Size::Lg" placeholder="Large" />
One-time code
A segmented input for verification codes: one box per character, feeding a hidden field so the form posts a single value. Typing advances, Backspace and the arrow keys move between boxes, and pasting or an SMS autofill is spread across them. Use :numeric="false" for alphanumeric codes such as recovery codes.
<x-pajak-form::otp name="otp-default" />
<x-pajak-form::otp name="otp-length" label="PIN" :length="4" />
@use('Pajak\Ui\Common\Enums\Size')
<x-pajak-form::otp name="otp-sm" label="Small" :size="Size::Sm" />
<x-pajak-form::otp name="otp-md" label="Medium" :size="Size::Md" />
<x-pajak-form::otp name="otp-lg" label="Large" :size="Size::Lg" />
<x-pajak-form::otp name="otp-recovery" label="Recovery code" :length="8" :numeric="false" />
<x-pajak-form::otp name="otp-error" error="The code is invalid or has expired." />
<form id="otp-autosubmit-form" onsubmit="event.preventDefault(); document.getElementById('otp-autosubmit-result').textContent = 'Submitted: ' + this.elements.code.value"> <x-pajak-form::otp name="code" :autosubmit="true" /> <p id="otp-autosubmit-result" class="ex-label">Fill every box to submit the form.</p> </form>
Number
A convenience wrapper around x-pajak-form::input with type="number". Pass min, max, and step directly as HTML attributes.
<x-pajak-form::number name="qty" placeholder="0" min="0" max="100" step="1" />
@use('Pajak\Ui\Common\Enums\State')
<x-pajak-form::number name="num-filled" value="42" min="0" max="100" />
<x-pajak-form::number name="num-err" placeholder="0" :state="State::Error" />
<x-pajak-form::number name="num-ok" value="10" :state="State::Success" />
<x-pajak-form::number name="num-dis" value="5" :disabled="true" />
Tel
A convenience wrapper around x-pajak-form::input with type="tel". Accepts all the same props as Input. Pass a TelPattern enum case for built-in locale patterns and placeholders.
<x-pajak-form::tel name="phone" placeholder="+1 555 000 0000" />
@use('Pajak\Ui\Form\Enums\TelPattern')
<x-pajak-form::tel
name="phone-sk"
:pattern="TelPattern::Sk"
:placeholder="TelPattern::Sk->placeholder()"
/>
<x-pajak-form::tel
name="phone-cz"
:pattern="TelPattern::Cz"
:placeholder="TelPattern::Cz->placeholder()"
/>
<x-pajak-form::tel
name="phone-intl"
:pattern="TelPattern::International"
:placeholder="TelPattern::International->placeholder()"
/>
@use('Pajak\Ui\Common\Enums\State')
<x-pajak-form::tel name="tel-filled" value="+421 912 345 678" />
<x-pajak-form::tel name="tel-err" placeholder="+421 912 345 678" :state="State::Error" />
<x-pajak-form::tel name="tel-ok" value="+421 912 345 678" :state="State::Success" />
<x-pajak-form::tel name="tel-dis" value="+421 912 345 678" :disabled="true" />
Url
A convenience wrapper around x-pajak-form::input with type="url". Accepts all the same props as Input.
<x-pajak-form::url name="website" placeholder="https://example.com" />
@use('Pajak\Ui\Common\Enums\State')
<x-pajak-form::url name="url-filled" value="https://example.com" />
<x-pajak-form::url name="url-err" placeholder="https://example.com" :state="State::Error" />
<x-pajak-form::url name="url-ok" value="https://valid.com" :state="State::Success" />
<x-pajak-form::url name="url-dis" value="https://readonly.com" :disabled="true" />
Textarea
A resizable multi-line text field. Accepts the same state modifiers as Input.
@use('Pajak\Ui\Common\Enums\State')
<x-pajak-form::textarea name="ta-default" placeholder="Write something…" />
<x-pajak-form::textarea name="ta-error" :state="State::Error" placeholder="Error state" />
<x-pajak-form::textarea name="ta-disabled" placeholder="Disabled" :disabled="true" :rows="2" />
@use('Pajak\Ui\Common\Enums\State')
<x-pajak-form::textarea name="ta-success" value="Looks good." :state="State::Success" :rows="3" />
<x-pajak-form::textarea name="ta-prefilled" value="This is a pre-filled message." :rows="3" />
<x-pajak-form::textarea name="ta-err-inline" placeholder="Write something…" error="This field is required." :rows="3" />
Select
A custom-styled select backed by a native <select>. Supports single select, searchable, option groups with metadata, and multiselect with dismissible chips. JavaScript upgrades the trigger and dropdown while keeping the native element accessible and form-submittable.
@use('Pajak\Ui\Common\Enums\State')
<x-pajak-form::select name="sel-default" placeholder="Choose a plan…">
<option value="free">Free</option>
<option value="pro">Pro</option>
<option value="enterprise">Enterprise</option>
</x-pajak-form::select>
<x-pajak-form::select name="sel-searchable" placeholder="Choose a country" :searchable="true"> <option value="sk">Slovakia</option> <option value="cz">Czech Republic</option> <option value="de">Germany</option> <option value="at">Austria</option> <option value="pl">Poland</option> <option value="hu">Hungary</option> </x-pajak-form::select>
<x-pajak-form::select name="sel-grouped" placeholder="Select income source" :searchable="true"> <optgroup label="Recent"> <option value="acme" data-meta="PIT-11">Acme s.r.o.</option> <option value="globex" data-meta="PIT-11">Globex s.r.o.</option> </optgroup> <optgroup label="Other sources"> <option value="freelance" data-meta="PIT-36">Freelance / B2B</option> <option value="rental" data-meta="PIT-28">Rental income</option> </optgroup> </x-pajak-form::select>
<x-pajak-form::select name="sel-deductions" placeholder="Add deduction…" :multiple="true" :options="['internet' => 'Internet relief', 'charity' => 'Charity donation', 'rehab' => 'Rehabilitation', 'children' => 'Children relief']" :value="['internet']" />
<x-pajak-form::select name="sel-preselected" value="pro"> <option value="free">Free</option> <option value="pro">Pro</option> <option value="enterprise">Enterprise</option> </x-pajak-form::select>
<x-pajak-form::select name="sel-err" placeholder="Choose a plan…" error="Please select a plan."> <option value="free">Free</option> <option value="pro">Pro</option> <option value="enterprise">Enterprise</option> </x-pajak-form::select>
<x-pajak-form::select name="sel-disabled" placeholder="Disabled select" :disabled="true"> <option value="a">Option A</option> </x-pajak-form::select>
<x-pajak-form::select name="sel-disabled-options" placeholder="Choose a plan…" :disabled-options="['enterprise']"> <option value="free">Free</option> <option value="pro">Pro</option> <option value="enterprise">Enterprise (sold out)</option> </x-pajak-form::select>
Checkbox
A styled checkbox with an optional label and description. Pass :checked="true" to pre-check it, :disabled="true" to disable, and :indeterminate="true" for the dash state. Wrap related checkboxes in <x-pajak-form::checkbox-group> for a select-all.
<x-pajak-form::checkbox name="cb-label" value="1" label="Remember me" /> <x-pajak-form::checkbox name="cb-checked" value="1" label="Checked by default" :checked="true" /> <x-pajak-form::checkbox name="cb-desc" value="1" label="Subscribe to updates" description="Get notified about new features and releases." /> <x-pajak-form::checkbox name="cb-disabled" value="1" label="Disabled" :disabled="true" />
<x-pajak-form::checkbox name="roles[]" value="admin" label="Admin" description="Full system access." :checked="true" /> <x-pajak-form::checkbox name="roles[]" value="editor" label="Editor" description="Can create and edit content." :checked="true" /> <x-pajak-form::checkbox name="roles[]" value="viewer" label="Viewer" description="Read-only access." /> <x-pajak-form::checkbox name="roles[]" value="billing" label="Billing" description="Manage invoices and subscriptions." :disabled="true" />
<x-pajak-form::checkbox name="partial" value="1" label="Partially selected" :indeterminate="true" /> <x-pajak-form::checkbox name="checked" value="1" label="Checked" :checked="true" /> <x-pajak-form::checkbox name="unchecked" value="1" label="Unchecked" />
<x-pajak-form::checkbox-group label="Users module" select-all="Select all"> <x-pajak-form::checkbox name="permissions[]" value="users.view" label="View users" :checked="true" /> <x-pajak-form::checkbox name="permissions[]" value="users.create" label="Create users" /> <x-pajak-form::checkbox name="permissions[]" value="users.edit" label="Edit users" /> <x-pajak-form::checkbox name="permissions[]" value="users.delete" label="Delete users" :disabled="true" /> </x-pajak-form::checkbox-group>
<x-pajak-form::checkbox name="terms" value="1" label="I accept the terms and conditions" error="You must accept the terms to continue." />
Radio
Standard radio buttons. Group them by sharing the same name. Supports labels, descriptions, and disabled state.
<x-pajak-form::radio name="plan" value="free" label="Free" description="Up to 3 projects, community support." :checked="true" /> <x-pajak-form::radio name="plan" value="pro" label="Pro" description="Unlimited projects, priority support." /> <x-pajak-form::radio name="plan" value="enterprise" label="Enterprise" description="Custom SLA, dedicated support." :disabled="true" />
<x-pajak-form::radio name="plan-err" value="free" label="Free" error="Please select a plan." /> <x-pajak-form::radio name="plan-err" value="pro" label="Pro" /> <x-pajak-form::radio name="plan-err" value="enterprise" label="Enterprise" />
Radio Card
A card-style radio button. Great for plan or option pickers where you need more visual weight than a plain radio.
<x-pajak-form::radio-card name="tier" value="free" label="Free" hint="Up to 3 projects, community support." :checked="true" /> <x-pajak-form::radio-card name="tier" value="pro" label="Pro" hint="Unlimited projects, priority support." /> <x-pajak-form::radio-card name="tier" value="enterprise" label="Enterprise" hint="Custom SLA and dedicated support." :disabled="true" />
<x-pajak-form::radio-card name="storage" value="10gb" label="10 GB" hint="Great for personal use." :checked="true"> <x-heroicon-o-circle-stack width="20" height="20" /> </x-pajak-form::radio-card> <x-pajak-form::radio-card name="storage" value="100gb" label="100 GB" hint="Ideal for teams and collaboration."> <x-heroicon-o-circle-stack width="20" height="20" /> </x-pajak-form::radio-card> <x-pajak-form::radio-card name="storage" value="1tb" label="1 TB" hint="For large-scale storage needs."> <x-heroicon-o-circle-stack width="20" height="20" /> </x-pajak-form::radio-card>
Toggle
A switch/toggle control. Uses a hidden checkbox as the underlying input, so it participates in forms normally. Three sizes: sm, md, lg.
@use('Pajak\Ui\Common\Enums\Size')
<x-pajak-form::toggle name="tog-sm" :size="Size::Sm" label="Small toggle" />
<x-pajak-form::toggle name="tog-md" label="Medium toggle (default)" :checked="true" />
<x-pajak-form::toggle name="tog-lg" :size="Size::Lg" label="Large toggle" />
<x-pajak-form::toggle name="tog-dis" label="Disabled" :disabled="true" :checked="true" />
<x-pajak-form::toggle name="tog-bare" /> <x-pajak-form::toggle name="tog-bare-on" :checked="true" /> <x-pajak-form::toggle name="tog-bare-dis" :disabled="true" />
<x-pajak-form::toggle name="tog-err" label="Enable notifications" error="You must enable notifications to continue." />
Repeater
A dynamic field group that lets users add and remove rows of inputs. Write plain field-key names inside the slot - the component automatically composes name, id, and for attributes into array notation for both server-rendered rows and dynamically added rows.
<x-pajak-form::repeater name="tags"> <x-pajak-form::input name="tag" placeholder="Tag" /> </x-pajak-form::repeater>
<x-pajak-form::repeater name="links" label="Links" :count="2" add-label="Add link"> <x-pajak-form::input name="label" label="Label" placeholder="Home" /> <x-pajak-form::url name="url" label="URL" placeholder="https://example.com" style="flex:2" /> </x-pajak-form::repeater>
<x-pajak-form::repeater name="emails" label="Email addresses" :min="1" :max="3" :count="1" add-label="Add email"> <x-pajak-form::email name="address" placeholder="[email protected]" /> </x-pajak-form::repeater>
Slider
A draggable range control. Supports single and range (two-thumb) modes, an optional value bubble, label, suffix, disabled state, and inline error message.
<x-pajak-form::slider name="volume" :value="40" />
<x-pajak-form::slider name="brightness" label="Brightness" :value="60" suffix="%" />
<x-pajak-form::slider name="quality" label="Quality" :value="75" suffix="%" :show-bubble="true" />
<x-pajak-form::slider name="price" label="Price range" :range="true" :value="20" :value-max="80" suffix="€" />
<x-pajak-form::slider name="vol-dis" label="Single (disabled)" :value="50" :disabled="true" /> <x-pajak-form::slider name="price-dis" label="Range (disabled)" :range="true" :value="25" :value-max="75" :disabled="true" />
<x-pajak-form::slider name="rating" label="Rating" :value="0" error="Please select a value greater than 0." />
Colour Picker
A hex colour field with a round swatch. Clicking the swatch opens a picker panel with a large saturation/brightness area, a hue slider and optional preset swatches; typing a valid 6-digit hex updates the picker live. Only the text input is submitted, as #RRGGBB — no third-party library needed.
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | — | name of the hex text input (the submitted value) |
label | string|null | null | Label text; no label rendered when null |
value | string|null | null | Initial colour as #RRGGBB; empty/invalid shows a checkerboard swatch |
:swatches | array | [] | Preset colours (#RRGGBB) shown under the hue slider |
:inline | bool | false | Always-open, bigger picker without the swatch button |
placeholder | string|null | #RRGGBB | Placeholder text |
:size | Size | Size::Md | Input size |
disabled | bool | false | Disables the swatch and the text input |
error | string|null | null | Error message shown below the field |
<x-pajak-form::color-picker name="primary_color" label="Primary colour" value="#2A9D8F" />
<x-pajak-form::color-picker name="brand_color" label="Brand colour" value="#5386E4" :swatches="['#5386E4', '#2A9D8F', '#E9C46A', '#F4A261', '#E76F51', '#8E5CF6', '#1A1F2E', '#FFFFFF']" />
<x-pajak-form::color-picker name="theme_color" label="Theme colour" value="#E76F51" :inline="true" :swatches="['#E76F51', '#2A9D8F', '#5386E4', '#8E5CF6', '#1A1F2E']" />
@use('Pajak\Ui\Common\Enums\Size')
{{-- Empty: checkerboard swatch until a valid hex is typed or picked --}}
<x-pajak-form::color-picker name="accent_color" label="Accent colour" />
<x-pajak-form::color-picker name="brand_color" label="Brand colour" value="not-a-colour" error="Enter a valid hex colour, e.g. #2A9D8F." />
<x-pajak-form::color-picker name="locked_color" label="Locked colour" value="#5386E4" :disabled="true" />
<x-pajak-form::color-picker name="small_color" label="Small" value="#E76F51" :size="Size::Sm" />
File
A styled <input type="file">. Displays the selected filename inline. No JavaScript required.
<x-pajak-form::file name="attachment" label="Attachment" />
<x-pajak-form::file name="document" label="Document" accept=".pdf,image/*" placeholder="Select a PDF or image…" />
<x-pajak-form::file name="attachment" label="Attachment" error="The file must be smaller than 2 MB." />
<x-pajak-form::file name="attachment" label="Attachment" disabled />
Dropzone
A drag-and-drop upload zone with a file list. Supports single and multiple file modes. Works with standard HTML form submission - no async upload required. Pre-populate files via the :files prop for edit forms.
<x-pajak-form::dropzone name="documents" label="Documents" />
<x-pajak-form::dropzone name="contract" label="Contract" :multiple="false" />
<x-pajak-form::dropzone name="attachments" label="Attachments" accept=".pdf,image/*" />
@php
use Pajak\Ui\Common\Dto\UploadedFile;
$files = [
new UploadedFile(id: 42, name: 'contract.pdf', size: 214_000),
new UploadedFile(id: 43, name: 'invoice.pdf', size: 198_000),
];
@endphp
<x-pajak-form::dropzone name="documents" label="Documents" :files="$files" />
<x-pajak-form::dropzone name="documents" label="Documents" error="At least one document is required." />
@php
use Pajak\Ui\Common\Dto\UploadedFile;
$files = [
new UploadedFile(id: 42, name: 'contract.pdf', size: 214_000),
];
@endphp
<x-pajak-form::dropzone name="documents" label="Documents" :files="$files" disabled />
Avatar
A circular image upload with an initials fallback. Suitable for profile photos. Clicking the circle or the upload button opens the file picker. Standard form submission - no async upload.
<x-pajak-form::avatar name="avatar" label="Profile photo" initials="JK" />
<x-pajak-form::avatar name="avatar" label="Profile photo" initials="JK" src="https://i.pravatar.cc/200" />
<x-pajak-form::avatar name="avatar" label="Profile photo" initials="JK" error="Please upload a valid image." />
<x-pajak-form::avatar name="avatar" label="Profile photo" initials="JK" src="https://i.pravatar.cc/200" disabled />
Image Grid
A thumbnail grid for multiple image uploads. Selected images appear immediately as previews. Works with standard form submission. Pre-populate with existing images via the :images prop for edit forms.
<x-pajak-form::image-grid name="photos" label="Photos" />
@php
use Pajak\Ui\Common\Dto\UploadedFile;
$images = [
new UploadedFile(id: 10, name: 'receipt_1.jpg', url: 'https://picsum.photos/seed/r1/200/200'),
new UploadedFile(id: 11, name: 'receipt_2.jpg', url: 'https://picsum.photos/seed/r2/200/200'),
new UploadedFile(id: 12, name: 'receipt_3.jpg', url: 'https://picsum.photos/seed/r3/200/200'),
];
@endphp
<x-pajak-form::image-grid name="receipts" label="Receipt photos" :images="$images" />
<x-pajak-form::image-grid name="photos" label="Photos" error="At least one photo is required." />
@php
use Pajak\Ui\Common\Dto\UploadedFile;
$images = [
new UploadedFile(id: 10, name: 'receipt_1.jpg', url: 'https://picsum.photos/seed/r1/200/200'),
new UploadedFile(id: 11, name: 'receipt_2.jpg', url: 'https://picsum.photos/seed/r2/200/200'),
];
@endphp
<x-pajak-form::image-grid name="receipts" label="Receipt photos" :images="$images" disabled />