Skip to content

Form ​

Form consists of input, select, radio, checkbox and other controls, for collecting, validating, and submitting data.

NameCategoryDescriptionTypeDefault
inline? StyleWhether to use inline form layoutbooleanfalse
labelWidth? StyleLabel widthnumber | string—
labelPosition? StyleLabel position'left' | 'right' | 'top''right'
hideRequiredAsterisk? StyleWhether to hide red asteriskbooleanfalse
requiredAsteriskPosition? StyleAsterisk position'left' | 'right''left'
FormItemlabelWidth? StyleLabel widthnumber | string—
disabled? StateWhether to disable formbooleanfalse
FormItemdisabled? StateWhether disabledbooleanfalse
rules? BehaviorForm validation rules (supports Zod schema)FormRules—
statusIcon? BehaviorWhether to show status icon after validationbooleanfalse
showMessage? BehaviorWhether to show validation error messagebooleantrue
FormItemrequired? BehaviorWhether requiredbooleanfalse
FormItemrules? BehaviorValidation rules (supports Zod schema or required shorthand)FormItemRule[]—
FormItemshowMessage? BehaviorWhether to show validation errorbooleantrue
FormItemfor? BehaviorLabel's for attribute, associates with a specific form controlstring—
model? ContentForm data objectRecord<string, any>—
labelSuffix? ContentLabel suffixstring—
FormItemprop? ContentKey name of modelstring | string[]—
FormItemlabel? ContentLabel textstring—
FormItemerror? ContentError messagestring—
validate? EventTriggered after field validation(prop: string, isValid: boolean, message: string) => void—
FormItemdefault? SlotForm item content—
FormItemlabel? SlotCustom label—
FormItemerror? SlotCustom error message—
validate? ExposeValidate the whole form(callback?: FormValidateCallback) => Promise<boolean>—
validateField? ExposeValidate specific fields(props?: string[], callback?: FormValidateCallback) => Promise<boolean>—
resetFields? ExposeReset form fields(props?: string[]) => void—
clearValidate? ExposeClear validation status(props?: string[]) => void—

Basic Usage ​

Basic form data control, including various form items.

<template>
  <px-form :model="form" label-width="80px">
    <px-form-item label="Name">
      <px-input v-model="form.name" placeholder="Enter name" />
    </px-form-item>
    <px-form-item label="Email">
      <px-input v-model="form.email" placeholder="Enter email" />
    </px-form-item>
    <px-form-item label="Active">
      <px-switch v-model="form.active" />
    </px-form-item>
    <px-form-item>
      <px-button type="primary" @click="onSubmit">Submit</px-button>
      <px-button @click="onReset">Reset</px-button>
    </px-form-item>
  </px-form>
</template>

<script setup lang="ts">
import { PxMessage } from 'sakana-element';
import { reactive } from 'vue';

const form = reactive({
  name: '',
  email: '',
  active: false,
});

const onSubmit = () => {
  PxMessage.success('Submit!');
};

const onReset = () => {
  form.name = '';
  form.email = '';
  form.active = false;
};
</script>

Form Validation ​

Form validation uses Zod schemas. Each rule can provide a schema (Zod type) or use the required shorthand for simple required checks.

<template>
  <px-form ref="formRef" :model="form" :rules="rules" label-width="80px">
    <px-form-item label="Name" prop="name">
      <px-input v-model="form.name" placeholder="Enter name" />
    </px-form-item>
    <px-form-item label="Email" prop="email">
      <px-input v-model="form.email" placeholder="Enter email" />
    </px-form-item>
    <px-form-item>
      <px-button type="primary" @click="onSubmit">Submit</px-button>
      <px-button @click="onReset">Reset</px-button>
    </px-form-item>
  </px-form>
</template>

<script setup lang="ts">
import { PxMessage } from 'sakana-element';
import { reactive, ref } from 'vue';
import { z } from 'zod';

const formRef = ref();

const form = reactive({
  name: '',
  email: '',
});

const rules = {
  name: [
    { schema: z.string().min(1, 'Please input name'), trigger: 'blur' },
    { schema: z.string().min(2).max(20, 'Length should be 2 to 20'), trigger: 'blur' },
  ],
  email: [
    { schema: z.string().min(1, 'Please input email'), trigger: 'blur' },
    { schema: z.string().email('Please input a valid email'), trigger: 'blur' },
  ],
};

const onSubmit = async () => {
  try {
    await formRef.value.validate();
    PxMessage.success('Submit success!');
  } catch {
    PxMessage.danger('Validation failed');
  }
};

const onReset = () => {
  formRef.value.resetFields();
};
</script>

Inline Form ​

Set inline to display form items in a horizontal row, useful for search forms and filters.

<template>
  <px-form ref="formRef" :model="form" inline label-width="60px">
    <px-form-item label="Name" prop="name">
      <px-input v-model="form.name" placeholder="Name" />
    </px-form-item>
    <px-form-item label="Email" prop="email">
      <px-input v-model="form.email" placeholder="Email" />
    </px-form-item>
    <px-form-item>
      <px-button type="primary" @click="onSearch">Search</px-button>
    </px-form-item>
  </px-form>
</template>

<script setup lang="ts">
import { PxMessage } from 'sakana-element';
import { reactive, ref } from 'vue';

const formRef = ref();
const form = reactive({
  name: '',
  email: '',
});

const onSearch = () => {
  PxMessage.success('Search submitted!');
};
</script>

Label Position ​

You can change the position of form field labels by setting label-position attribute.

<template>
  <div class="demo-form">
    <div class="buttons">
      <px-button @click="labelPosition = 'left'">Left</px-button>
      <px-button @click="labelPosition = 'right'">Right</px-button>
      <px-button @click="labelPosition = 'top'">Top</px-button>
    </div>
    <px-form :model="form" :label-position="labelPosition" label-width="80px">
      <px-form-item label="Name">
        <px-input v-model="form.name" placeholder="Enter name" />
      </px-form-item>
      <px-form-item label="Email">
        <px-input v-model="form.email" placeholder="Enter email" />
      </px-form-item>
      <px-form-item>
        <px-button type="primary" @click="onSubmit">Submit</px-button>
        <px-button @click="onCancel">Cancel</px-button>
      </px-form-item>
    </px-form>
  </div>
</template>

<script setup lang="ts">
import { reactive, ref } from 'vue';

const labelPosition = ref<'left' | 'right' | 'top'>('right');

const form = reactive({
  name: '',
  email: '',
});

function onSubmit() {}

function onCancel() {
  form.name = '';
  form.email = '';
}
</script>

<style scoped>
.demo-form .buttons {
  margin-bottom: 16px;
  display: flex;
  gap: 8px;
}
</style>

Status Icon ​

Set status-icon to show check/close icons after field validation.

<template>
  <px-form ref="formRef" :model="form" :rules="rules" status-icon label-width="80px">
    <px-form-item label="Name" prop="name">
      <px-input v-model="form.name" placeholder="Enter name" />
    </px-form-item>
    <px-form-item label="Email" prop="email">
      <px-input v-model="form.email" placeholder="Enter email" />
    </px-form-item>
    <px-form-item>
      <px-button type="primary" @click="onSubmit">Validate</px-button>
      <px-button @click="onReset">Reset</px-button>
    </px-form-item>
  </px-form>
</template>

<script setup lang="ts">
import { reactive, ref } from 'vue';
import { z } from 'zod';

const formRef = ref();
const form = reactive({
  name: '',
  email: '',
});

const rules = {
  name: [{ schema: z.string().min(1, 'Name is required'), trigger: 'blur' }],
  email: [{ schema: z.string().email('Invalid email'), trigger: 'blur' }],
};

const onSubmit = async () => {
  try {
    await formRef.value.validate();
  } catch {
    // validation failed
  }
};

const onReset = () => {
  formRef.value.resetFields();
};
</script>

Disabled ​

Set disabled on the form to disable all form controls.

<template>
  <px-form :model="form" disabled label-width="80px">
    <px-form-item label="Name" prop="name">
      <px-input v-model="form.name" placeholder="Enter name" />
    </px-form-item>
    <px-form-item label="Email" prop="email">
      <px-input v-model="form.email" placeholder="Enter email" />
    </px-form-item>
    <px-form-item label="Active" prop="active">
      <px-switch v-model="form.active" />
    </px-form-item>
    <px-form-item>
      <px-button type="primary" disabled>Submit</px-button>
    </px-form-item>
  </px-form>
</template>

<script setup lang="ts">
import { reactive } from 'vue';

const form = reactive({
  name: 'Sakana',
  email: 'sakana@example.com',
  active: true,
});
</script>