Skip to content
🌏 Translated with the assistance of DeepSeek and ChatGPT

Form

Used to collect information.

Basic usage

Form uses model to pass the form data object and rules to pass validation rules; in FormItem, field sets the form item field for validation, reset, and other operations.

FormItem's rule takes precedence over Form's rules for the same field.

When manually triggering validation using the Form component's validate method, it ignores the trigger condition configured on rules or rule, validates all existing FormItems, and stops at the first failing rule.

Additionally, note that the field property of FormItem is not reactive.

Please select...
<template>
	<px-form
		:model="form"
		:rules="rules"
		style="width: 500px"
		@submit="submitHandler"
		ref="formRef"
	>
		<px-form-item label="Input" field="input">
			<px-input v-model="form.input" placeholder="Please input..."></px-input>
		</px-form-item>
		<px-form-item label="Radio" field="radio">
			<px-radio-group
				v-model="form.radio"
				:options="radioOptions"
				variant="retro"
			></px-radio-group>
		</px-form-item>
		<px-form-item label="Checkbox" field="checkbox">
			<px-checkbox-group v-model="form.checkbox" :options="checkboxOptions"></px-checkbox-group>
		</px-form-item>
		<px-form-item label="Number" field="number">
			<px-input-number v-model="form.number" placeholder="Please input..."></px-input-number>
		</px-form-item>
		<px-form-item label="Tags" field="tags">
			<px-input-tag v-model="form.tags" placeholder="Press enter to confirm..."></px-input-tag>
		</px-form-item>
		<px-form-item label="Text" field="text">
			<px-textarea v-model="form.text" placeholder="Please input text..."></px-textarea>
		</px-form-item>
		<px-form-item label="Switch" field="switch">
			<px-switch v-model="form.switch"></px-switch>
		</px-form-item>
		<px-form-item label="Select" field="select">
			<px-select
				:options="options"
				v-model="form.select"
				placeholder="Please select..."
			></px-select>
		</px-form-item>
		<px-form-item label="Nest" field="nest.value">
			<px-input v-model="form.nest.value" placeholder="Please input..."></px-input>
		</px-form-item>
		<px-form-item label="Email" field="email">
			<px-input v-model="form.email" placeholder="Please email..."></px-input>
		</px-form-item>
		<px-form-item label="URL" field="url">
			<px-input v-model="form.url" placeholder="Please URL..."></px-input>
		</px-form-item>
		<px-form-item label="Slider" field="slider">
			<px-slider v-model="form.slider"></px-slider>
		</px-form-item>
		<px-form-item label="Number String" field="numberString">
			<px-input v-model="form.numberString" placeholder="Please number..."></px-input>
		</px-form-item>
		<px-space justify="end">
			<px-button native-type="submit">Submit</px-button>
			<px-button theme="info" native-type="reset" style="margin-left: 8px">Reset</px-button>
		</px-space>
	</px-form>
</template>
<script setup lang="ts">
import { Form } from '@pixelium/web-vue'

// If on-demand import
// import { Form } from '@pixelium/web-vue/es'

import { ref, shallowRef } from 'vue'

const form = ref({
	input: '',
	number: 0,
	tags: [] as string[],
	text: '',
	nest: {
		value: ''
	},
	select: null as null | string,
	email: '',
	url: '',
	numberString: '',
	switch: false,
	radio: null as null | string,
	checkbox: [] as string[],
	slider: 10
})

const rules = {
	input: { required: true, message: 'Please input' },
	select: { required: true, message: 'Please select' },
	switch: { required: true, message: 'Please select' },
	number: { min: 10, message: 'Min is 10' },
	tags: [
		{ required: true, message: 'Please input tags' },
		{ maxLength: 5, message: 'Length less than or equal 5' }
	],
	text: { required: true, message: 'Just a tip', level: 'warning' },
	'nest.value': { required: true, message: 'Please input' },
	email: { required: true, email: true, message: 'Please input email' },
	url: { required: true, url: true, message: 'Please input a URL' },
	numberString: { required: true, numberString: true, message: 'Please input number' },
	radio: {
		required: true,
		validator(value: string) {
			return value !== 'Yes' ? 'Please select Yes' : undefined
		}
	},
	checkbox: [
		{ required: true, message: 'Please select' },
		{ maxLength: 2, message: 'You can select up to 2 items' }
	],
	slider: { max: 90, message: 'Max is 90' }
}

const options = ref(['vue', 'react', 'angular'])
const radioOptions = ref(['Yes', 'No'])
const checkboxOptions = ref(['A', 'B', 'C', 'D'])

const formRef = shallowRef<null | InstanceType<typeof Form>>(null)
const submitHandler = () => {
	formRef.value?.validate().then(({ isValid }) => {
		if (isValid) {
			console.log('submit')
		}
	})
}
</script>

useForm returns an object for manipulating the form, which can be passed to the Form's form property.

Either the model or form property of Form must be provided.

<template>
	<div style="width: 500px">
		<px-form :form="userForm" :rules="userRules" label-auto-width>
			<px-form-item field="username" label="Username">
				<px-input v-model="userForm.model.value.username" placeholder="Username"></px-input>
			</px-form-item>
			<px-form-item field="email" label="Email">
				<px-input v-model="userForm.model.value.email" placeholder="Email"></px-input>
			</px-form-item>
			<px-space justify="end">
				<px-button @click="handleClearValidationUser" theme="info">Clear Validation</px-button>
				<px-button @click="handleResetUser" theme="warning">Reset</px-button>
				<px-button @click="handleSubmitUser">Submit</px-button>
			</px-space>
		</px-form>
	</div>
</template>

<script setup lang="ts">
import { useForm } from '@pixelium/web-vue'

// When on-demand import
// import { useForm } from '@pixelium/web-vue/es'

const userForm = useForm({
	initialValues: { username: '', email: '' }
})

const userRules = {
	username: [{ required: true, message: 'Please input username' }],
	email: [{ required: true, email: true, message: 'Please input valid email' }]
}

const handleSubmitUser = () => {
	userForm.validate().then(({ isValid }) => {
		if (isValid) {
			console.log('Submit User Form')
		}
	})
}

const handleResetUser = () => {
	userForm.reset()
}

const handleClearValidationUser = () => {
	userForm.clearValidation()
}
</script>

Custom validation

Use validator to provide custom validation rules.

The Answer to the Great Question Of Life, the Universe and Everything...

<template>
	<px-form :model="form" :rules="rules" style="width: 600px" ref="formRef">
		<p>The Answer to the Great Question Of Life, the Universe and Everything...</p>
		<px-form-item label="Answer" field="number" label-align="left">
			<px-input-number v-model="form.number"></px-input-number>
		</px-form-item>
	</px-form>
</template>
<script setup lang="ts">
import { ref } from 'vue'

const form = ref({
	number: 0
})

const rules = {
	number: {
		validator: (value: number | null) => {
			if (value === 42) {
				return
			}
			return 'Could you think again?'
		}
	}
}
</script>

Disabled & Readonly

Set the form's disabled state using disabled and the readonly state using readonly.

The disabled or readonly attribute of the Form component affects all button components within it (including Button and ButtonGroup) and the data input components within each FormItem, while the disabled or readonly attribute of an individual FormItem only affects the button and data input components within that specific FormItem.

These two properties follow an 'OR' logic throughout the component hierarchy: if any level—Form, FormItem, or the component itself—is set to disabled or readonly, the component will be rendered in that state.

Disabled

Readonly

<template>
	<px-space>
		<px-form
			:model="form"
			:rules="rules"
			style="width: 500px"
			@submit="submitHandler"
			ref="formRef"
			disabled
		>
			<h4>Disabled</h4>
			<px-form-item label="Username" field="username">
				<px-input v-model="form.username" placeholder="Please input username..."></px-input>
			</px-form-item>
			<px-form-item label="Email" field="email">
				<px-input v-model="form.email" placeholder="Please email..."></px-input>
			</px-form-item>
			<px-space justify="end">
				<px-button native-type="submit">Submit</px-button>
				<px-button theme="info" native-type="reset" style="margin-left: 8px">Reset</px-button>
			</px-space>
		</px-form>
		<px-form
			:model="form"
			:rules="rules"
			style="width: 500px"
			@submit="submitHandler"
			ref="formRef"
			readonly
		>
			<h4>Readonly</h4>
			<px-form-item label="Username" field="username">
				<px-input v-model="form.username" placeholder="Please input username..."></px-input>
			</px-form-item>
			<px-form-item label="Email" field="email">
				<px-input v-model="form.email" placeholder="Please email..."></px-input>
			</px-form-item>
			<px-space justify="end">
				<px-button native-type="submit">Submit</px-button>
				<px-button theme="info" native-type="reset" style="margin-left: 8px">Reset</px-button>
			</px-space>
		</px-form>
	</px-space>
</template>
<script setup lang="ts">
import { Form } from '@pixelium/web-vue'

// If on-demand import
// import { Form } from '@pixelium/web-vue/es'

import { ref, shallowRef } from 'vue'

const form = ref({
	username: '',
	email: ''
})

const rules = {
	username: { required: true, message: 'Please input' },
	email: { required: true, email: true, message: 'Please input email' }
}

const formRef = shallowRef<null | InstanceType<typeof Form>>(null)
const submitHandler = () => {
	formRef.value?.validate().then(({ isValid }) => {
		if (isValid) {
			console.log('submit')
		}
	})
}
</script>

Label alignment

Set label alignment with labelAlign.

<template>
	<px-space direction="vertical">
		<px-form :model="form" label-align="top" style="width: 500px">
			<px-form-item label="Input" field="input">
				<px-input v-model="form.input"></px-input>
			</px-form-item>
		</px-form>
		<px-form :model="form" style="width: 500px" label-align="left">
			<px-form-item label="Input" field="input">
				<px-input v-model="form.input"></px-input>
			</px-form-item>
		</px-form>
		<px-form :model="form" style="width: 500px">
			<px-form-item label="Input" field="input">
				<px-input v-model="form.input"></px-input>
			</px-form-item>
		</px-form>
	</px-space>
</template>
<script setup lang="ts">
import { ref } from 'vue'

const form = ref({
	input: ''
})
</script>

Child element width

Use labelProps and contentProps to modify the Col component props for the label and content areas.

When labelAutoWidth is set, the label area width becomes adaptive and the content area width will change accordingly.

<template>
	<px-space direction="vertical">
		<px-form
			:model="form"
			style="width: 500px"
			:label-props="{ span: 4 }"
			:content-props="{ span: 20 }"
		>
			<px-form-item label="Input" field="input">
				<px-input v-model="form.input"></px-input>
			</px-form-item>
		</px-form>
		<px-form :model="form" style="width: 500px" label-auto-width>
			<px-form-item label="Input" field="input">
				<px-input v-model="form.input"></px-input>
			</px-form-item>
		</px-form>
	</px-space>
</template>
<script setup lang="ts">
import { ref } from 'vue'

const form = ref({
	input: ''
})
</script>

Form size

The form is available in different sizes.

The size property of the Form component affects all button components within it (including Button and ButtonGroup) and the data input components within each FormItem.

For button components and data input components inside Form and FormItem, if the size property is not provided or is undefined, it will be set to match the Form's size property; if explicitly set, the provided value takes precedence.

<template>
	<px-space direction="vertical">
		<px-radio-group v-model="formSize" :options="radioSizeOptions"></px-radio-group>
		<px-form
			label-auto-width
			:model="form"
			:size="formSize"
			style="width: 500px"
			@submit="submitHandler"
		>
			<px-form-item label="Input" field="input">
				<px-input v-model="form.input"></px-input>
			</px-form-item>
			<px-form-item label="Number" field="number">
				<px-input-number v-model="form.number"></px-input-number>
			</px-form-item>
			<px-form-item label="Radio" field="radio">
				<px-radio-group
					v-model="form.radio"
					:options="radioOptions"
					variant="retro"
				></px-radio-group>
			</px-form-item>
			<px-form-item label="Checkbox" field="checkbox">
				<px-checkbox-group
					v-model="form.checkbox"
					:options="checkboxOptions"
				></px-checkbox-group>
			</px-form-item>
			<px-form-item label="Switch" field="switch">
				<px-switch v-model="form.switch"></px-switch>
			</px-form-item>
			<px-space justify="end">
				<px-button native-type="submit">Submit</px-button>
			</px-space>
		</px-form>
	</px-space>
</template>
<script setup lang="ts">
import { ref } from 'vue'

const form = ref({
	input: 'text',
	number: 114,
	radio: 'Yes',
	switch: false,
	checkbox: [] as string[]
})

const submitHandler = () => {
	console.log('submit')
}

const radioOptions = ref(['Yes', 'No'])
const radioSizeOptions = ref([
	{ label: 'Small', value: 'small' },
	{ label: 'Medium', value: 'medium' },
	{ label: 'Large', value: 'large' }
])

const checkboxOptions = ref(['A', 'B', 'C', 'D'])

const formSize = ref('medium')
</script>

API

useForm

ts
function useForm<T extends Record<string | number, any> = Record<string | number, any>>(options?: {
    initialValues?: T;
}): UseFormReturn<T>

export interface UseFormReturn<
	T extends Record<string | number, any> = Record<string | number, any>
> {
	model: Ref<T>
	validate: (field?: string | string[]) => FormValidateResult
	reset: (field?: string | string[]) => void
	clearValidation: (field?: string | string[]) => void
	register: (registerOptions: UseFormRegisterOptions) => void
}

FormProps

AttributeTypeOptionalDefaultDescriptionVersion
modelRecord<number | string, any>TrueThe form data object. Either form or model must be provided.0.0.3
formFormInstanceTrueForm object returned by useForm, used to manipulate the form via a hook. Either form or model must be provided.0.0.3
rulesRecord<string, RuleItem | RuleItem[]>TrueValidation rules.0.0.3
disabledbooleanTruefalseWhether the form is disabled.0.0.3
readonlybooleanTruefalseWhether the form is read-only.0.0.3
size'small' | 'medium' | 'large'True'medium'Form size.0.0.3
labelAlign'left' | 'right' | 'top'True'right'Label alignment.0.0.3
showAsteriskbooleanTrueWhether to show an asterisk.0.0.3
asteriskPlacement'left' | 'right' | 'end'True'left'Position of the asterisk.0.0.3
labelAutoWidthbooleanTruefalseEnable auto width for form item labels.0.0.3
rowPropsRowPropsTrueProps for the form item row container.0.0.3
labelPropsColPropsTrueProps for the form item's label column.0.0.3
contentPropsColPropsTrueProps for the form item's content column.0.0.3

UseFormReturn

AttributeTypeOptionalDefaultDescriptionVersion
modelRef<Record<string | number, any>>FalseThe form data object.0.0.3
validate(field?: string | string[]) => FormValidateResultFalseManually triggers form validation. Validates all fields when no parameters are provided. Can only be called after the Form is mounted.0.0.3
reset(field?: string | string[]) => voidFalseManually triggers form reset. Resets all fields when no parameters are provided. Can only be called after the Form is mounted.0.0.3
clearValidation(field?: string | string[]) => voidFalseClears the form validation status. Clears validation for all fields when no parameters are provided. Can only be called after the Form is mounted.0.0.3

FormEvents

EventParameterDescriptionVersion
submitform: Record<number | string, any>, event: EventCallback for native form submit.0.0.3
resetform: Record<number | string, any>, event: EventCallback for native form reset.0.0.3

FormSlots

SlotParameterDescriptionVersion
defaultUsed to render form items.0.0.3

FormExpose

AttributeTypeOptionalDefaultDescriptionVersion
validate(field?: string | string[]) => FormValidateResultFalseManually trigger form validation; without arguments validates all fields.0.0.3
reset(field?: string | string[]) => voidFalseManually trigger form reset; without arguments resets all fields.0.0.3
clearValidation(field?: string | string[]) => voidFalseClear validation state; without arguments clears all fields.0.0.3

RuleItem

AttributeTypeOptionalDefaultDescriptionVersion
requiredbooleanTruefalseWhether the field is required.0.0.3
messagestringTrueError message shown on validation failure; an empty string will not trigger an error.0.0.3
triggerRuleTrigger | RuleTrigger[]True['change', 'blur']Event that triggers validation.0.0.3
typeFieldType | FieldType[]TrueField type validation.0.0.3
maxnumberTrueMaximum value limit, only for numeric values.0.0.3
minnumberTrueMinimum value limit, only for numeric values.0.0.3
maxLengthnumberTrueMaximum length limit, applicable when the value is a string or array.0.0.3
minLengthnumberTrueMinimum length limit, applicable when the value is a string or array.0.0.3
emailbooleanTruefalseWhether the value must be an email address (applies when value is a string).0.0.3
urlbooleanTruefalseWhether the value must be a URL (applies when value is a string).0.0.3
numberStringbooleanTruefalseWhether the value must be a numeric string (applies when value is a string).0.0.3
levelRuleLevelTrue'error'Failure level; only 'error' will cause the form validation to fail.0.0.3
validator(value: any, model: Record<number | string, any>) => string | void | Promise<void | string>TrueCustom validation function that returns an error message string; a falsy/empty return indicates success.0.0.3

FormItemProps

AttributeTypeOptionalDefaultDescriptionVersion
fieldstringTrueThe associated form field name. Supports field path syntax, e.g. 'user[0].info.name'. This property is not reactive.0.0.3
labelstringTrueLabel text.0.0.3
ruleRuleItem | RuleItem[]TrueValidation rules.0.0.3
disabledbooleanTrueWhether to disable. The final disabled state is determined by OR operation with disabled from Form.0.0.3
readonlybooleanTrueWhether to be read-only. The final read-only state is determined by OR operation with readonly from Form.0.0.3
labelAlign'left' | 'right' | 'top'TrueLabel alignment for this item.0.0.3
showAsteriskbooleanTrueWhether to show an asterisk.0.0.3
asteriskPlacement'left' | 'right' | 'end'TruePosition of the asterisk.0.0.3
rowPropsRowPropsTrueProps for the form item's row container.0.0.3
labelPropsColPropsTrueProps for the form item's label column.0.0.3
contentPropsColPropsTrueProps for the form item's content column.0.0.3

FormItemSlots

SlotParameterDescriptionVersion
tipmessage: string, level: RuleLevelValidation tip slot.0.0.3
extraExtra content slot located below the content area.0.0.3
labelCustom label slot.0.0.3
defaultForm item content slot.0.0.3

RuleLevel, FieldType, RuleTrigger, FormValidateResult

ts
export type RuleLevel = 'error' | 'warning' | 'success' | 'normal'
export type FieldType = 'number' | 'string' | 'boolean' | 'array' | 'dict' | 'function' | 'date'
export type RuleTrigger = 'blur' | 'change' | 'input'

export type FormValidateResult = Promise<{
	isValid: boolean
	results: Record<
		string,
		PromiseSettledResult<{
			message: string
			level: RuleLevel
		}>
	>
}>