Skip to content

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

javascript
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/tags
  • FTxSelectBox - 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 lazyLoad prop)
    • Search functionality - Built-in search with API-based filtering
  • q-toggle - Toggle switch
  • q-checkbox - Single checkbox
  • q-radio - Radio button
  • q-option-group - Radio/checkbox groups with labels
  • q-date - Date picker with popup and calendar
  • q-time - Time picker with popup
  • q-editor - Rich text editor (WYSIWYG)
  • q-file - File upload with drag & drop support
  • q-btn - Button component
  • q-separator - Visual separator
  • Custom Components - Any Vue component via component prop

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 input
    • decimalAllowed - 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:

  1. ✅ Conditional show/hide - Show fields based on other field values

    • Use show property (boolean or function: (form, field) => boolean)
    • Fields are completely hidden (not rendered) when show is false
    • Conditions are reactive - fields appear/disappear as form values change
  2. ✅ Conditional enable/disable - Enable/disable based on conditions

    • Use disable property (boolean or function: (form, field) => boolean)
    • Disabled fields are still visible but cannot be edited
    • Fields are automatically disabled when form loading is true
    • Conditions are reactive - fields enable/disable as form values change
  3. ✅ Conditional required - Make fields required based on conditions

    • Use required property (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

See the Conditional Features section below for detailed examples.

Basic Usage

Simple Form

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

vue
<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:

  1. Using q-select - Basic multi-select with chips when using the multiple prop
  2. Using FTxSelectBox - Advanced multi-select with tags/chips, virtual scrolling, and async loading (recommended for large datasets)
vue
<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 lazyLoad prop)
  • 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.

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

vue
<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:

vue
<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:

  • show can be a boolean or a function that receives (form, field) and returns a boolean
  • Fields are completely hidden (not rendered) when show is false
  • Conditions are reactive - fields appear/disappear as form values change

Conditional Enable/Disable ✅

Fields can be conditionally enabled or disabled using the disable property:

vue
<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:

  • disable can 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 loading is true
  • Conditions are reactive - fields enable/disable as form values change

Conditional Required ✅

Fields can be conditionally required using the required property:

vue
<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:

  • required can 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:

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

vue
<template>
  <FTxForm
    :formConfig="formConfig"
    v-model:form="formData"
    :dialogProps="{ dialog: true, persistent: true }"
    :title="'Create User'"
    @submit="handleSubmit"
  />
</template>

Props

PropTypeDefaultDescription
formConfigObject{}Form configuration object (required)
formObject{}Form data object (v-model:form)
loadingBooleanfalseShow loading state
submittingBooleanfalseShow submitting state
titleString''Form title (for dialog mode)
dialogPropsObject{}Dialog properties for sidebar mode
dropDownBtnsArray[]Dropdown button configurations

Events

EventPayloadDescription
submitformEmitted when form is submitted
update:formformEmitted when form data changes
option-selected{ btnName, action }Emitted when dropdown option is selected

Methods (via ref)

MethodDescription
resetForm()Reset form to initial state

Form Config Structure

typescript
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) - use multiple prop
    • ✅ Async select with virtual scrolling is available via FTxSelectBox as a custom component
    • ✅ Searchable select is already supported via FTxQSelect

Phase 3: Conditional Logic ✅ (Completed)

  • ✅ Conditional field visibility - Implemented - Use show property (boolean or function)
  • ✅ Conditional enable/disable - Implemented - Use disable property (boolean or function)
  • ✅ Conditional required - Implemented - Use required property (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

  • FormHeader - Form header component
  • FormRows - Row layout component
  • FormColumns - Column layout component
  • FormFields - Field list component
  • FormField - Individual field component
  • FTxSidebarForm - Sidebar form wrapper

Validation Helpers

Import validation helpers from @ftx/ui:

javascript
import { 
  requiredRule, 
  onlyInteger, 
  intValueValidation, 
  getFieldRules 
} from '@ftx/ui'

Notes

  • All Quasar component props are supported via the props property
  • Custom components can be used via the component property
  • Field slots allow complete customization of any field
  • Form validation is automatic on submit
  • Loading states are handled automatically

See Also

Released under the MIT License.