FTxForm
A powerful, flexible form component built on Vue 3 and Quasar Framework for creating complex, validated forms with minimal configuration.
Overview
FTxForm provides a comprehensive form solution with:
- Flexible Layout System: Support for rows, columns, and nested structures
- Multiple Field Types: Text inputs, selects, dates, toggles, and more
- Built-in Validation: Required fields, custom rules, and validation helpers
- Dialog & Sidebar Modes: Use forms in dialogs or as sidebar panels
- Loading States: Built-in loading indicators and skeleton screens
- Action Management: Submit, delete, and custom action buttons
- Responsive Design: Works seamlessly across all screen sizes
Installation
import { FTxForm } from '@ftx/ui'Current Features
Form Structure & Layout
Supported Layout Types
- Rows Layout (
formConfig.rows) - Horizontal row-based layout with columns - Columns Layout (
formConfig.columns) - Vertical column-based layout - Fields Layout (
formConfig.fields) - Simple flat field list - Nested Structures - Rows can contain nested rows and columns
- Card Sections - Wrap sections in cards with titles and descriptions
Field Types
Currently Supported Components
q-input- Text input with all Quasar input types (text, number, email, password, textarea, search, tel, url)q-select- Dropdown select (using FTxQSelect) with single and multiple selection, searchable, multi-select with chips/tagsFTxSelectBox- Advanced select component with:- ✅ Multi-select with tags/chips - Visual chip/tag display for selected items
- ✅ Virtual scrolling with lazy loading - Efficient handling of large datasets via API
- ✅ Async select - Load data on scroll for better performance (via
lazyLoadprop) - ✅ Search functionality - Built-in search with API-based filtering
q-toggle- Toggle switchq-checkbox- Single checkboxq-radio- Radio buttonq-option-group- Radio/checkbox groups with labelsq-date- Date picker with popup and calendarq-time- Time picker with popupq-editor- Rich text editor (WYSIWYG)q-file- File upload with drag & drop supportq-btn- Button componentq-separator- Visual separator- Custom Components - Any Vue component via
componentprop
Validation System
- Required Fields - Mark fields as required with automatic validation
- Custom Rules - Add custom validation rules per field
- Integer Validation - Built-in integer-only validation
- Decimal Validation - Decimal number validation with precision control
- Input Constraints:
integerOnly- Only allow integer inputdecimalAllowed- Allow decimal numbers (max 10 digits before, 2 after decimal)maxLength- Maximum character length- Space prevention on empty fields
Form Features
- Form Header - Title, description, toggle fields, and custom buttons
- Form Actions - Submit, delete, and custom action buttons with loading states
- Loading States - Form-level and field-level loading indicators
- Dialog & Sidebar Mode - Forms rendered in sidebar dialogs
- Slots - Custom content slots for flexibility
- ✅ Conditional Field Visibility - Show/hide fields based on other field values (Implemented)
- ✅ Conditional Enable/Disable - Enable/disable fields based on conditions (Implemented)
- ✅ Conditional Required - Make fields required based on conditions (Implemented)
Conditional Logic Features ✅
All conditional logic features are fully implemented and ready to use:
✅ Conditional show/hide - Show fields based on other field values
- Use
showproperty (boolean or function:(form, field) => boolean) - Fields are completely hidden (not rendered) when
showisfalse - Conditions are reactive - fields appear/disappear as form values change
- Use
✅ Conditional enable/disable - Enable/disable based on conditions
- Use
disableproperty (boolean or function:(form, field) => boolean) - Disabled fields are still visible but cannot be edited
- Fields are automatically disabled when form
loadingistrue - Conditions are reactive - fields enable/disable as form values change
- Use
✅ Conditional required - Make fields required based on conditions
- Use
requiredproperty (boolean or function:(form, field) => boolean) - Required fields show an asterisk (*) in the label
- Validation rules are automatically applied/removed based on the required state
- Conditions are reactive - required state changes as form values change
- Use
See the Conditional Features section below for detailed examples.
Basic Usage
Simple Form
<template>
<FTxForm
:formConfig="formConfig"
v-model:form="formData"
:loading="loading"
@submit="handleSubmit"
/>
</template>
<script setup>
import { ref } from 'vue'
import { FTxForm } from '@ftx/ui'
const formData = ref({
name: '',
email: '',
age: null
})
const loading = ref(false)
const formConfig = {
title: 'User Information',
description: 'Please fill in your details',
fields: [
{
name: 'name',
component: 'q-input',
label: 'Full Name',
required: true,
props: {
outlined: true,
dense: true
}
},
{
name: 'email',
component: 'q-input',
label: 'Email Address',
required: true,
props: {
type: 'email',
outlined: true,
dense: true
}
},
{
name: 'age',
component: 'q-input',
label: 'Age',
required: true,
integerOnly: true,
props: {
type: 'number',
outlined: true,
dense: true
}
}
],
actions: [
{
label: 'Submit',
props: {
type: 'submit',
color: 'primary',
unelevated: true
}
}
]
}
const handleSubmit = (form) => {
console.log('Form submitted:', form)
// Handle form submission
}
</script>Form with Rows and Columns
<script setup>
const formConfig = {
title: 'Advanced Form',
rows: [
{
columns: [
{
class: 'col-6',
fields: [
{
name: 'firstName',
component: 'q-input',
label: 'First Name',
required: true,
props: { outlined: true, dense: true }
}
]
},
{
class: 'col-6',
fields: [
{
name: 'lastName',
component: 'q-input',
label: 'Last Name',
required: true,
props: { outlined: true, dense: true }
}
]
}
]
},
{
card: true,
cardTitle: 'Contact Information',
columns: [
{
class: 'col-12',
fields: [
{
name: 'email',
component: 'q-input',
label: 'Email',
required: true,
props: { type: 'email', outlined: true, dense: true }
}
]
}
]
}
]
}
</script>Form with Multi-Select (Tags/Chips)
You can use multi-select with tags/chips in two ways:
- Using
q-select- Basic multi-select with chips when using themultipleprop - Using
FTxSelectBox- Advanced multi-select with tags/chips, virtual scrolling, and async loading (recommended for large datasets)
<script setup>
const formConfig = {
fields: [
{
name: 'tags',
component: 'q-select',
label: 'Select Tags',
required: false,
props: {
multiple: true,
outlined: true,
dense: true,
options: ['Tag 1', 'Tag 2', 'Tag 3', 'Tag 4']
}
},
{
name: 'categories',
component: 'q-select',
label: 'Categories',
required: true,
props: {
multiple: true,
outlined: true,
dense: true,
use-chips: true,
options: [
{ label: 'Category 1', value: 'cat1' },
{ label: 'Category 2', value: 'cat2' },
{ label: 'Category 3', value: 'cat3' }
]
}
}
]
}
</script>Using FTxSelectBox in Forms (Multi-Select, Virtual Scrolling, Async Loading)
FTxSelectBox provides advanced select features including multi-select with tags/chips, virtual scrolling, and async data loading. Use it as a custom component for:
- Multi-select with tags/chips - Visual display of selected items as removable chips
- Virtual scrolling - Efficient rendering of large datasets
- Async select with lazy loading - Load data on scroll or when dropdown opens (via
lazyLoadprop) - API-based data loading - Fetch data from API endpoints dynamically
Note: Virtual scrolling and async select are provided through the lazyLoad prop, which enables data fetching when the dropdown opens and loads more data as the user scrolls.
<script setup>
import { FTxSelectBox } from '@ftx/ui'
const formConfig = {
fields: [
{
name: 'userId',
component: FTxSelectBox,
label: 'Select User',
required: true,
props: {
apiUrl: '/api/users',
optionLabel: 'name',
optionValue: 'id',
lazyLoad: true, // Enable lazy loading (virtual scrolling + async data)
rowsPerPage: 25, // Items per page for pagination
outlined: true,
dense: true
}
},
{
name: 'tags',
component: FTxSelectBox,
label: 'Select Tags',
required: false,
props: {
apiUrl: '/api/tags',
optionLabel: 'name',
optionValue: 'id',
multiple: true, // Enable multi-select with tags/chips
lazyLoad: true, // Virtual scrolling + async loading
maxSelectedPreview: 3, // Max chips to show before summary
rowsPerPage: 25,
outlined: true,
dense: true
}
}
]
}
</script>Form with Validation Rules
<script setup>
const formConfig = {
fields: [
{
name: 'password',
component: 'q-input',
label: 'Password',
required: true,
props: { type: 'password', outlined: true, dense: true },
rules: [
(val) => val.length >= 8 || 'Password must be at least 8 characters',
(val) => /[A-Z]/.test(val) || 'Password must contain uppercase letter',
(val) => /[0-9]/.test(val) || 'Password must contain a number'
]
}
]
}
</script>Conditional Features ✅
All conditional logic features are fully implemented and ready to use in production.
Conditional Field Visibility ✅
Fields can be conditionally shown or hidden based on other field values using the show property:
<script setup>
const formConfig = {
fields: [
{
name: 'accountType',
component: 'q-select',
label: 'Account Type',
required: true,
props: {
outlined: true,
dense: true,
options: ['basic', 'premium', 'enterprise']
}
},
{
name: 'companyName',
component: 'q-input',
label: 'Company Name',
// Show only when accountType is 'enterprise'
show: (form) => form.accountType === 'enterprise',
required: true,
props: { outlined: true, dense: true }
},
{
name: 'premiumFeature',
component: 'q-toggle',
label: 'Enable Premium Features',
// Show only when accountType is 'premium' or 'enterprise'
show: (form) => ['premium', 'enterprise'].includes(form.accountType),
props: { outlined: true }
}
]
}
</script>Features:
showcan be a boolean or a function that receives(form, field)and returns a boolean- Fields are completely hidden (not rendered) when
showisfalse - Conditions are reactive - fields appear/disappear as form values change
Conditional Enable/Disable ✅
Fields can be conditionally enabled or disabled using the disable property:
<script setup>
const formConfig = {
fields: [
{
name: 'isReadOnly',
component: 'q-toggle',
label: 'Read Only Mode',
props: { outlined: true }
},
{
name: 'email',
component: 'q-input',
label: 'Email',
// Disable when isReadOnly is true
disable: (form) => form.isReadOnly === true,
required: true,
props: {
type: 'email',
outlined: true,
dense: true
}
},
{
name: 'phone',
component: 'q-input',
label: 'Phone',
// Disable when form is submitting or email is empty
disable: (form) => !form.email || form.isReadOnly,
props: { outlined: true, dense: true }
}
]
}
</script>Features:
disablecan be a boolean or a function that receives(form, field)and returns a boolean- Disabled fields are still visible but cannot be edited
- Fields are automatically disabled when form
loadingistrue - Conditions are reactive - fields enable/disable as form values change
Conditional Required ✅
Fields can be conditionally required using the required property:
<script setup>
const formConfig = {
fields: [
{
name: 'contactMethod',
component: 'q-select',
label: 'Contact Method',
required: true,
props: {
outlined: true,
dense: true,
options: ['email', 'phone', 'both']
}
},
{
name: 'email',
component: 'q-input',
label: 'Email',
// Required only when contactMethod is 'email' or 'both'
required: (form) => ['email', 'both'].includes(form.contactMethod),
props: {
type: 'email',
outlined: true,
dense: true
}
},
{
name: 'phone',
component: 'q-input',
label: 'Phone',
// Required only when contactMethod is 'phone' or 'both'
required: (form) => ['phone', 'both'].includes(form.contactMethod),
props: {
type: 'tel',
outlined: true,
dense: true
}
},
{
name: 'address',
component: 'q-input',
label: 'Address',
// Required when accountType is 'enterprise' AND shipping is required
required: (form) => form.accountType === 'enterprise' && form.requiresShipping,
props: {
type: 'textarea',
outlined: true,
dense: true,
rows: 3
}
}
]
}
</script>Features:
requiredcan be a boolean or a function that receives(form, field)and returns a boolean- Required fields show an asterisk (*) in the label
- Validation rules are automatically applied/removed based on the required state
- Conditions are reactive - required state changes as form values change
Combining Conditional Features
You can combine all conditional features together:
<script setup>
const formConfig = {
fields: [
{
name: 'userType',
component: 'q-select',
label: 'User Type',
required: true,
props: {
outlined: true,
dense: true,
options: ['individual', 'business']
}
},
{
name: 'businessName',
component: 'q-input',
label: 'Business Name',
// Show only for business users
show: (form) => form.userType === 'business',
// Required only when shown
required: (form) => form.userType === 'business',
// Disable when form is processing
disable: (form) => form.isProcessing === true,
props: { outlined: true, dense: true }
},
{
name: 'taxId',
component: 'q-input',
label: 'Tax ID',
// Show only for business users
show: (form) => form.userType === 'business',
// Required when business name is provided
required: (form) => form.userType === 'business' && form.businessName,
props: { outlined: true, dense: true }
}
]
}
</script>Form in Dialog Mode
<template>
<FTxForm
:formConfig="formConfig"
v-model:form="formData"
:dialogProps="{ dialog: true, persistent: true }"
:title="'Create User'"
@submit="handleSubmit"
/>
</template>Props
| Prop | Type | Default | Description |
|---|---|---|---|
formConfig | Object | {} | Form configuration object (required) |
form | Object | {} | Form data object (v-model:form) |
loading | Boolean | false | Show loading state |
submitting | Boolean | false | Show submitting state |
title | String | '' | Form title (for dialog mode) |
dialogProps | Object | {} | Dialog properties for sidebar mode |
dropDownBtns | Array | [] | Dropdown button configurations |
Events
| Event | Payload | Description |
|---|---|---|
submit | form | Emitted when form is submitted |
update:form | form | Emitted when form data changes |
option-selected | { btnName, action } | Emitted when dropdown option is selected |
Methods (via ref)
| Method | Description |
|---|---|
resetForm() | Reset form to initial state |
Form Config Structure
interface FormConfig {
title?: string
description?: string
toggleFields?: Array<{
name: string
label: string
}>
rows?: Array<RowConfig>
columns?: Array<ColumnConfig>
fields?: Array<FieldConfig>
actions?: Array<ActionConfig>
}
interface FieldConfig {
name: string
component: string
label?: string
required?: boolean | ((form: Object, field?: Object) => boolean)
disable?: boolean | ((form: Object, field?: Object) => boolean)
show?: boolean | ((form: Object, field?: Object) => boolean)
integerOnly?: boolean
decimalAllowed?: boolean
maxLength?: number
rules?: Array<Function>
props?: Object
colClass?: string
}Upcoming Features
We're actively working on expanding FTxForm capabilities. Here's what's coming soon:
Phase 1: Essential Field Types ✅ (Completed)
- ✅ Checkbox and Radio support (
q-checkbox,q-radio,q-option-group) - Implemented - ✅ File upload (
q-file) - Implemented - ✅ Rich text editor (
q-editor) - Implemented - [ ] Advanced file uploader (
q-uploader) - Planned
Phase 2: Advanced Input Types (Near Future)
- Enhanced input types (masking, autocomplete, currency, phone, OTP)
- Date/time enhancements (datetime picker, date ranges)
- Select enhancements (cascading selects)
- Note:
- ✅ Multi-select with tags/chips is already supported via
q-select(FTxQSelect) - usemultipleprop - ✅ Async select with virtual scrolling is available via
FTxSelectBoxas a custom component - ✅ Searchable select is already supported via FTxQSelect
- ✅ Multi-select with tags/chips is already supported via
Phase 3: Conditional Logic ✅ (Completed)
- ✅ Conditional field visibility - Implemented - Use
showproperty (boolean or function) - ✅ Conditional enable/disable - Implemented - Use
disableproperty (boolean or function) - ✅ Conditional required - Implemented - Use
requiredproperty (boolean or function) - [ ] Dynamic field management - Planned
- [ ] Field calculations - Planned
Phase 4: Enhanced Validation (Near Future)
- Built-in validators (email, URL, phone, credit card, etc.)
- Async validation support
- Enhanced validation features
For the complete roadmap, see FTxForm Enhancement Roadmap
Related Components
FormHeader- Form header componentFormRows- Row layout componentFormColumns- Column layout componentFormFields- Field list componentFormField- Individual field componentFTxSidebarForm- Sidebar form wrapper
Validation Helpers
Import validation helpers from @ftx/ui:
import {
requiredRule,
onlyInteger,
intValueValidation,
getFieldRules
} from '@ftx/ui'Notes
- All Quasar component props are supported via the
propsproperty - Custom components can be used via the
componentproperty - Field slots allow complete customization of any field
- Form validation is automatic on submit
- Loading states are handled automatically