vkm-apps/x-form
VKM APPS | X-Form
✨ Supercharge your Laravel form building!
Create beautiful, fully interactive forms in a single line of Blade code. No more repeating boilerplate layouts, validation classes, error handlers, and input styles! 🚀💻
X-Form is a highly polished collection of Blade components for Laravel 11, 12, and 13+, built on top of Livewire 3, Tailwind CSS 4, and AlpineJS 3. It makes form creation lightning-fast and fully interactive while ensuring complete customization via published configurations.
To enjoy full compatibility, please install the VKM JS plugins bundle: 👉 https://github.com/vkm-apps/vkm-js
Requirements
- PHP:
^8.1 - Laravel / Support:
^11.0 | ^12.0 | ^13.0 - Livewire:
^3.0 - AlpineJS:
^3.0 - Tailwind CSS:
^4.0
Installation & Setup
Install the package via Composer:
composer require vkm-apps/x-form
Install and publish the configuration files using the setup command:
php artisan x-form:install
[!NOTE] The install command automatically publishes the package configuration file to
config/x-form.php. You can customize styles, Tailwind classes, default icons, and other behavioral settings.
Available Components
Here is a summary of the available Blade components and their key features:
| Component Tag | Core Purpose | Special Features |
|---|---|---|
<x-form.input> |
Standard text/number inputs | Prepend/append slots, live validation, group sizing, tooltips/popovers |
<x-form.textarea> |
Multiline text input | Auto-resizing heights, character countdown counter, limit restriction |
<x-form.password> |
Password entry | Interactive visibility toggle (eye/eye-off icon) |
<x-form.select> |
Select dropdowns | Rich searchable dropdowns, inline search, native select fallback |
<x-form.checkbox> |
Checkboxes | Single/grouped layouts, nested modules with tooltip and group toggles |
<x-form.radio> |
Radio buttons | Consistent styling, horizontal/vertical layouts |
<x-form.date> |
Native date picker | Range date pickers, multi-locale, Livewire & plain HTML form bindings |
<x-form.disabled> |
Rich read-only displays | Inline actions (Copy, Link, Mail, Phone, Fax, Maps), currency formatting |
<x-form.money> |
Locale-aware currency inputs | Dynamic AlpineJS masking, automatic locale/currency formatting, raw float bindings, dynamic placeholders |
<x-form.editor> |
Rich text WYSIWYG editor | Formatting, colors, tables, YouTube embeds, custom image editor |
<x-form.editor-modal> |
Singleton table manager | Renders the shared table management modal |
<x-form.file> |
File uploader | File previews, drag-and-drop dropzones, multiple file support |
<x-form.file-url> |
File-URL selector | Integrated file manager popup to insert public file URLs directly |
<x-form.icon> |
SVG icon utility | Lightweight helper to render predefined system icons |
Global Features & Shared Attributes
All components inheriting from the core FormElement support a set of rich, interactive features that make writing beautiful, accessible interfaces straightforward:
1. Tooltips & Help Popovers
Add quick informational tips next to your labels automatically.
tooltip="Your message": Shows a small info icon next to the label that displays a tooltip on hover.help="Your rich HTML message": Shows an info icon that opens an AlpineJS popover dialog on click.
<x-form.input model="title" label="Title" tooltip="This is a short tooltip." />
<x-form.input model="slug" label="Slug" help="<strong>URL friendly</strong> slug. Only letters, numbers, and dashes are allowed." />
2. Required Markings
required: Adds a red asterisk (*) to the label automatically.
<x-form.input model="name" label="Name" required />
3. Prepend & Append Slots
Enables nesting icons, buttons, text badges, or custom HTML inside the input layout.
<x-slot:prepend>: Inserts content before the input field.<x-slot:append>: Inserts content after the input field.
<x-form.input model="price" label="Price" type="number">
<x-slot:prepend><span class="px-2 text-gray-500">$</span></x-slot:prepend>
<x-slot:append><span class="px-2 text-gray-500">USD</span></x-slot:append>
</x-form.input>
4. Livewire Model Modifiers
Binds model updates utilizing Livewire modifiers out of the box:
live: Updates the model on every keypress (wire:model.live).blur: Updates the model when input focus is lost (wire:model.live.blur).change: Updates the model when input selection changes (wire:model.live.change).
<x-form.input model="search" label="Search" live />
Input
A fully customizable input field with automated label generation, validation highlights, accessibility attributes, and error message outputs.
<x-form.input model="title" label="Title" />
Component Properties
| Attribute | Type | Default | Description |
|---|---|---|---|
model |
string|null |
null |
The Livewire model property to bind to. |
name |
string|null |
null |
Name attribute (defaults to model). |
label |
string|null |
null |
Text label display. |
type |
string |
'text' |
HTML input type (number, email, tel, url, text, etc.). |
placeholder |
string|null |
null |
Input placeholder text. |
icon |
string|null |
null |
Icon CSS classes (e.g. FontAwesome) displayed next to the label. |
required |
bool |
false |
Marks the field as required (red asterisk). |
tooltip |
string|null |
null |
Tooltip info text. |
help |
string|null |
null |
Rich HTML help popover content. |
group |
string|bool |
false |
Flex sizing wrapper. Values: 'sm', 'lg', 'xl', or false. |
validate |
string|bool |
false |
Client-side validation trigger. Values: 'blur', true (keyup), or false. |
border |
bool |
true |
Show input border. |
invalid |
bool |
false |
Manually force the input to show validation error styling. |
{{-- Large, instantly validating number input --}}
<x-form.input type="number" model="age" label="Age" group="lg" validate="blur" required />
Textarea
Textareas support character counts, maximum limits, auto-height resizing, and error bindings.
<x-form.textarea model="description" label="Description" placeholder="Enter details..." />
Component Properties
| Attribute | Type | Default | Description |
|---|---|---|---|
model |
string|null |
null |
The Livewire model property to bind to. |
name |
string|null |
null |
Name attribute. |
label |
string|null |
null |
Text label display. |
rows |
int |
5 |
Height size in rows. |
limit |
int |
0 |
Character limit. If > 0, turns count display into remaining counter. |
showCount |
bool |
true |
Show/hide the character counter underneath. |
icon |
string|null |
null |
Icon classes beside the label. |
required |
bool |
false |
Marks the field as required. |
tooltip |
string|null |
null |
Tooltip text. |
help |
string|null |
null |
Help popover content. |
{{-- Textarea with a 250-character limit counter --}}
<x-form.textarea model="bio" label="Biography" limit="250" rows="4" required />
Password
A secure password input that automatically renders a show/hide toggle button (eye icon) using AlpineJS under the hood.
<x-form.password model="password" label="New Password" required />
Component Properties
| Attribute | Type | Default | Description |
|---|---|---|---|
model |
string|null |
null |
The Livewire model property to bind to. |
name |
string|null |
null |
Name attribute. |
label |
string|null |
null |
Text label display. |
icon |
string|null |
null |
Icon classes next to the label. |
required |
bool |
false |
Marks the field as required. |
tooltip |
string|null |
null |
Tooltip text. |
help |
string|null |
null |
Help popover content. |
group |
string|null |
null |
Sized wrapper. Supported values: 'sm', 'lg', 'xl', or null. |
validate |
string|bool |
false |
Real-time validation trigger ('blur', true, or false). |
Select and Dropdown
Renders an interactive dropdown with custom searching, styled scrollbars, and dynamic state bindings. Alternatively, it can fall back to a native browser select element.
<x-form.select :list="$this->countryList" model="country" label="Country of Origin" />
Component Properties
| Attribute | Type | Default | Description |
|---|---|---|---|
list |
array|null |
['yes'=>1,'no'=>0] |
Options mapping array (formatted as Label => Value or Title => ID). |
model |
string|null |
null |
The Livewire model property to bind to. |
name |
string|null |
null |
Name attribute. |
label |
string|null |
null |
Text label display. |
title |
string |
'-' |
Default display placeholder text (e.g. "Select an option"). |
icon |
string|null |
null |
Prepend HTML or CSS class icon inside the select button. |
searchable |
bool |
false |
Enable/disable text filter search within the list. |
inline |
bool |
false |
Place the search input inline inside the popup instead of overlaying the select button. |
dropdown |
bool |
true |
Renders a styled custom dropdown. Set to false to fallback to native <select>. |
minWidth |
string |
'revert-layer' |
Set dropdown container minimum width (e.g. '250px'). |
maxHeight |
string |
'400px' |
Set dropdown container maximum height (e.g. '300px'). |
required |
bool |
false |
Marks the field as required. |
tooltip |
string|null |
null |
Tooltip text. |
help |
string|null |
null |
Help popover content. |
live |
bool |
false |
Force live updates immediately upon item selection. |
Options Array Format
Ensure arrays use string keys to preserve ordering on the frontend:
#[Computed]
public function countryList(): array
{
return [
'Greece' => 'gr',
'Italy' => 'it',
'Spain' => 'es',
];
}
Advanced Select Usage
{{-- Custom searchable dropdown with inline input --}}
<x-form.select
:list="$this->countryList"
model="country"
label="Country"
searchable
inline
title="Choose a destination..."
/>
{{-- Native browser select fallback --}}
<x-form.select
:list="$this->countryList"
model="country"
label="Country"
:dropdown="false"
/>
Checkboxes and Radio Buttons
Tailwind-styled choice groups supporting horizontal/vertical alignments, descriptions, tooltips, and interactive group toggles.
Single Checkbox (Boolean)
If you omit the :list attribute, the component renders a single checkbox representing a boolean value (e.g., binds to a boolean property true/false). The label is displayed inline next to the checkbox.
<x-form.checkbox model="remember_me" label="Remember Me" required />
Flat Checkbox Group
If you pass the :list attribute, the component renders a list of checkboxes matching the option keys and values. The label is displayed as a header above the list.
<x-form.checkbox :list="$this->optionsList" model="interests" label="Interests" />
Radio Group
<x-form.radio :list="$this->optionsList" model="gender" label="Gender" />
Component Properties (Checkbox & Radio)
| Attribute | Type | Default | Description |
|---|---|---|---|
list |
array|null |
null |
Options array (Title => Value). If null, renders a single boolean checkbox. |
model |
string|null |
null |
Livewire model binding. |
name |
string|null |
null |
Name attribute. |
label |
string|null |
null |
Label text. |
horizontal |
bool |
false |
Render list horizontally. (Vertical stack is the default). |
required |
bool |
false |
Marks the field as required. |
tooltip |
string|null |
null |
Tooltip icon and message text. |
help |
string|null |
null |
Help popover icon and HTML content. |
| Checkbox Only | |||
grouped |
bool |
false |
Enables nested category groups (requires multi-dimensional list). |
group |
bool |
false |
Alias for grouped. |
perColumn |
int |
20 |
Columns chunk sizes. |
toggle |
string|null |
null |
Livewire method called when category header checkbox is clicked (bypasses default AlpineJS toggle). |
tooltipKey |
string|null |
null |
Array key used for items tooltips when grouped is true. |
{{-- Horizontal row alignment for Radios --}}
<x-form.radio :list="$this->optionsList" model="gender" horizontal />
Grouped Checkboxes (With Header Checkboxes & Tooltips)
Grouped checkboxes are designed for complex nested layouts (e.g., system permissions categorized by module) and support dynamic tooltips and automatic header toggles.
You can use either:
<x-form.checkbox-group :list="$countries" model="selectedCountries" label="Destination Countries" />
or the group attribute alias:
<x-form.checkbox :list="$countries" model="selectedCountries" label="Destination Countries" group />
Header Checkbox Select-All: Each category header features a functional checkbox. Checking/unchecking the header checkbox toggles all items in that category client-side via AlpineJS. In addition, checking all individual items in a category automatically checks the header checkbox.
Example Array Structure:
$countries = [
'Europe' => [
['id' => 'gr', 'title' => 'Greece', 'description' => 'Greece is located in southeastern Europe.'],
['id' => 'it', 'title' => 'Italy', 'description' => 'Italy is a peninsula in the Mediterranean Sea.'],
],
'Asia' => [
['id' => 'jp', 'title' => 'Japan', 'description' => 'Japan is an island country in East Asia.'],
],
];
Custom Livewire Toggle Function (Optional):
If you want to run backend PHP code when a group header is clicked, pass the toggle attribute with your Livewire method name:
public function toggleGroup($groupName)
{
// $groupName is passed as 'Europe' or 'Asia'
// Custom select-all or deselect-all logic here...
}
<x-form.checkbox
:list="$countries"
model="selectedCountries"
label="Destination Countries"
group
toggle="toggleGroup"
tooltip-key="description"
/>
Date Picker
A powerful, native-feeling calendar date input wrapper that uses the AlpineJS date picker extension. It supports ranges, locales, and handles both Livewire property binding and normal HTML form submissions.
Component Properties
| Attribute | Type | Default | Description |
|---|---|---|---|
model |
string|null |
null |
Livewire model property. |
name |
string|null |
null |
Name attribute. |
label |
string|null |
null |
Text label display. |
range |
bool |
false |
Enable range picker (displays side-by-side start and end inputs). |
locale |
string |
'en' |
Locale language code (e.g. 'el', 'es', 'de'). |
required |
bool |
false |
Marks field as required. |
icon |
string|null |
null |
Custom icon beside label. |
tooltip |
string|null |
null |
Tooltip info text. |
help |
string|null |
null |
Help popover content. |
Single Date Picker
<x-form.date model="appointment_date" label="Appointment Date" />
Date Range Picker
When range is enabled, the component displays two side-by-side inputs for selecting start and end boundaries.
<x-form.date model="travel_dates" range label="Travel Duration" />
Locales Support
Pass language codes to initialize localized date displays:
<x-form.date model="appointment_date" locale="el" label="Ημερομηνία" />
Native HTML Form Mode
If the model attribute is omitted, the date picker works as a plain form input writing to a hidden field for standard PHP POST requests.
- Single date mode: Submits to the input
nameparameter. - Range date mode: Submits to
[name]_startand[name]_end(e.g., ifname="travel_dates", POST fields will betravel_dates_startandtravel_dates_end).
{{-- Submits birth_date --}}
<x-form.date name="birth_date" label="Date of Birth" />
{{-- Submits hotel_dates_start and hotel_dates_end --}}
<x-form.date name="hotel_dates" range label="Hotel Booking" />
Disabled Inputs
The x-form.disabled component displays non-editable content in a clean, consistent format. It is equipped with quick-action wrapper tags that support instant interactivity without writing extra Javascript.
<x-form.disabled label="API Token" value="vkm_token_abcdef123456" copy />
Component Properties
| Attribute | Type | Default | Description |
|---|---|---|---|
label |
string|null |
null |
Text label display. |
value |
string|null |
null |
Value string to display. |
icon |
string|null |
null |
Icon classes or custom SVG string overlay. |
currency |
string|null |
null |
Currency symbol formatting based on code (e.g., 'USD', 'EUR'). |
copy |
bool |
false |
Adds a copy-to-clipboard button with instant feedback. |
link |
bool |
false |
Renders the value as a clickable link that opens in a new tab. |
mail |
bool |
false |
Renders a mailto: link to open the default email client. |
phone |
bool |
false |
Renders a tel: link for direct call features. |
fax |
bool |
false |
Renders a fax: link. |
map |
bool |
false |
Renders a link that opens Google Maps with the address value preloaded. |
tooltip |
string|null |
null |
Tooltip info text. |
Advanced Usage Examples
Display Currency Formatting: Prepend locale-aware currency symbols dynamically resolved from the ISO code.
<x-form.disabled label="Invoice Value" value="1,240.00" currency="USD" />
Custom Icon Overlay:
<x-form.disabled label="Status" value="Active" icon="fa-solid fa-circle-check" />
Prepend & Append Slots:
<x-form.disabled value="vasilis.milopoulos@gmail.com" mail>
<x-slot:prepend><span class="text-xs text-gray-500">[Verified]</span></x-slot:prepend>
</x-form.disabled>
Money Input
A locale-aware, highly polished money input component built with AlpineJS masking (x-mask:dynamic). It formats user input dynamically with correct thousands and decimal separators based on locale and currency settings, while sending and maintaining a raw numeric float value to Livewire or traditional form submissions.
<x-form.money model="price" label="Unit Price" />
Key Features
- Automatic Locale & Currency Resolution: Using PHP's
NumberFormatterclass, the component automatically resolves the decimal separator, thousands separator, currency symbol, symbol position (prefix vs. suffix), and default precision. - Dynamic Placeholders: If no explicit
placeholderis provided, the component dynamically generates a formatted placeholder representing the currency format (e.g.1,000.00foren-US/USD, or1.000,00forde-DE/EUR). - Dual Bindings: A visible, styled text input handles the masked presentation using AlpineJS, while a hidden input stores the raw, unformatted float value (
rawValue) for clean database storing and Livewire updates. - Livewire & Plain HTML Form Support: Integrates seamlessly with Livewire's binding modifiers (
live,blur,change) and supports traditional form submissions using thenameattribute.
Component Properties
| Attribute | Type | Default | Description |
|---|---|---|---|
model |
string|null |
null |
The Livewire model property to bind to. |
name |
string|null |
null |
Name attribute for traditional forms (defaults to model). |
label |
string|null |
null |
Text label display. |
placeholder |
string|null |
null |
Custom input placeholder. Defaults to a dynamically generated placeholder (e.g., 1,000.00) based on resolved settings. |
currency |
string|null |
null |
ISO 3-letter currency code (e.g. 'USD', 'EUR', 'GBP'). Falls back to config('x-form.currency'). |
locale |
string|null |
null |
Locale tag (e.g. 'en_US', 'el_GR', 'de_DE', 'en') or language ('en', 'de', etc.). Falls back to application locale. |
precision |
int |
2 |
Number of decimal places. Falls back to currency's default precision resolved via NumberFormatter. |
icon |
string|null |
null |
Icon classes next to the label. |
required |
bool |
false |
Marks the field as required (red asterisk). |
tooltip |
string|null |
null |
Tooltip info text. |
help |
string|null |
null |
Rich HTML help popover content. |
group |
string|bool |
false |
Sizing wrapper. Supported values: 'sm', 'lg', 'xl', or false. |
validate |
string|bool |
false |
Client-side validation trigger. Supported values: 'blur', true (keyup), or false. |
border |
bool |
true |
Show input border. |
invalid |
bool |
false |
Force the input to display validation error styling. |
Advanced Examples
Custom Currency & Locale: Explicitly define a different currency and locale. The input automatically positions the symbol (prefix or suffix) and formats numbers correctly.
{{-- German locale with Euro (symbol € placed as suffix, e.g. 1.000,00) --}}
<x-form.money model="price" label="Price" currency="EUR" locale="de-DE" />
{{-- US locale with GBP (symbol £ placed as prefix, e.g. £1,000.00) --}}
<x-form.money model="price" label="Price in Pounds" currency="GBP" locale="en-US" />
Custom Decimal Precision: You can specify custom decimal precision (e.g., for commodities, exchange rates, or precision pricing).
<x-form.money model="rate" label="Exchange Rate" precision="4" />
Rich Text Editor
An HTML WYSIWYG editor containing formatting tools, custom text and highlight colors, table structures, and links. It also has features for YouTube embeds, image sizing, and Livewire File Manager integrations.
<x-form.editor model="html_content" label="Rich Text Content" with-filemanager />
Component Properties
| Attribute | Type | Default | Description |
|---|---|---|---|
model |
string|null |
null |
Livewire model property to bind to. |
label |
string|null |
null |
Text label display. |
content |
string|null |
null |
Initial HTML content. |
watchFor |
string|null |
null |
Tracked variable (e.g. record ID) to force reactive HTML updates when records switch. |
withFilemanager |
bool |
false |
Enable Livewire File Manager button for inserting media URLs. |
[!IMPORTANT] Singleton Table Editor Requirement To use the rich text editor's custom table builder, you must render the shared editor modal singleton once in your application's layout file (usually right before the closing
</body>tag):<x-form.editor-modal />
Reactive Array Updates
If you are updating dynamic models and arrays inside Livewire and need the text editor's HTML to stay reactive without breaking input focus, pass the identifier of the tracked array inside the watchFor property:
<x-form.editor model="item.content" :watchFor="$item['id']" label="Editable Item" />
File Upload
Allows users to upload files via standard buttons or high-fidelity, drag-and-drop dropzones.
<x-form.file model="attachment" label="Document Attachment" button="Choose File..." />
Component Properties
| Attribute | Type | Default | Description |
|---|---|---|---|
model |
string|null |
null |
Livewire model binding. |
name |
string|null |
null |
Name attribute. |
label |
string|null |
null |
Header label. |
button |
string|null |
null |
Custom button text (e.g. 'Choose File...'). |
multiple |
string|bool|null |
null |
Enable multiple file uploads. Set to true or 'multiple'. |
dropzone |
bool |
false |
Enable drag-and-drop upload zone layout. |
help |
string|null |
null |
Information text (usually displayed in dropzone or below button). |
required |
bool |
false |
Marks field as required. |
tooltip |
string|null |
null |
Tooltip info text. |
Dropzone Uploader
Adds a dashed drag-and-drop zone that supports drop events and file list displays.
<x-form.file
model="attachments"
label="Upload Gallery"
dropzone
multiple
help="PNG, JPG or WEBP up to 5MB"
/>
File URL Browser
The x-form.file-url component combines a standard input field with the package's Livewire File Manager. Clicking the input allows the user to browse files inside their storage disk and attaches the selected file's public URL directly back to the text input.
<x-form.file-url model="avatar_url" label="Avatar Image URL" placeholder="Browse or paste URL..." />
Component Properties
| Attribute | Type | Default | Description |
|---|---|---|---|
model |
string|null |
null |
The Livewire model property to bind to. |
label |
string|null |
null |
Text label display. |
placeholder |
string|null |
null |
Input placeholder text. |
required |
bool |
false |
Marks field as required. |
tooltip |
string|null |
null |
Tooltip info text. |
help |
string|null |
null |
Help popover content. |
validate |
string|bool |
false |
Real-time validation trigger ('blur', true, or false). |
border |
bool |
true |
Show input border. |
Icon Helper
A lightweight, centralized Blade component that renders vector SVGs from the package's default icon directory. This avoids duplicating inline SVG codes throughout layouts.
<x-form.icon name="trash" class="text-red-500 size-6" />
Component Properties
| Attribute | Type | Default | Description |
|---|---|---|---|
name |
string |
(Required) | Predefined icon name key. |
class |
string |
'size-5' |
Custom CSS classes applied to the SVG tag. |
Predefined Icon Names
The following keys are supported out-of-the-box:
paragraph, headings, textcase, fontsize, bold, italic, underline, strikethrough, superscript, subscript, code, textcolor, backgroundcolor, alignment, alignleft, aligncenter, alignright, ul, ol, letter_list, table, link, video, image, cleanup, chevron-up, chevron-down, chevron-left, chevron-right, settings, trash.
Customization
Publishing Component Views
If you need to tweak the HTML architecture of the inputs directly, publish the view files to your application directory:
php artisan vendor:publish --tag=x-form:views
The view files will be copied to resources/views/vendor/x-form/, allowing you to modify them without losing package update capabilities.
Custom Styling in config/x-form.php
The styling is completely driven by configuration values. You can change global background behaviors, focus states, sizes, and borders:
'inputs' => [
'bg' => 'bg-black/5 dark:bg-white/5 backdrop-blur-md shadow-xs',
'border' => 'border border-black/5 dark:border-white/10',
'focus' => 'focus:ring-2 focus:ring-blue-500/50 dark:focus:ring-blue-400/50 focus:shadow-md outline-none',
],
License
This package is open-sourced software licensed under the MIT license.