Skip to content

FormPro

Easily create a form with simple configuration
  • Encapsulated based on NForm

Basic Usage

vue
vue
<template>
  <FormPro ref="formPro" v-model="modelValue" :form-config="formConfig">
    <template #operation>
      <n-flex>
        <n-button type="primary" @click="submit">Submit</n-button>
        <n-button @click="reset">Reset</n-button>
      </n-flex>
    </template>
  </FormPro>
</template>

<script lang="ts" setup>
/** Form field types */
interface FormFields {
  name?: string;
  age?: number;
}

/** Form configuration */
const formConfig: FormPro.FormItemConfig[] = [
  { name: "name", label: "Name" },
  { name: "age", label: "Age", component: "number" },
];

/** Form data */
const modelValue = ref<FormFields>({});

/** Form instance */
const formProRef = useTemplateRef("formPro");

/** Submit */
const submit = async () => {
  await formProRef.value?.validate(); // Validate
  console.log("Form submitted:", modelValue.value);
};

const reset = () => formProRef.value?.reset();
</script>

Form Validation

  • Pass rules in form-props to enable form validation.
  • Supports all Form Props parameters except model.
vue
vue
<template>
  <FormPro
    ref="formPro"
    v-model="modelValue"
    :form-config="formConfig"
    :form-props="formProps"
  >
    ...
  </FormPro>
</template>

<script lang="ts" setup>
import { type FormProps } from "naive-ui";

/** Form validation */
const formProps: FormProps = {
  rules: {
    name: [{ required: true, message: "Please enter your name" }],
    age: [{ required: true, message: "Please enter your age" }],
  },
};
</script>

Form Item Configuration

You can configure props, slots, and formItemProps for each form item individually.

⚠️ Note

props and slots depend on the component you use.

  • If component is not set, the default is NInput's Input-Props and Input-Slots.
  • If component is set to select, only NSelect props and slots are available.
  • Even if you don't know what configurations are available for each component's props and slots, you don't need to worry as there will be TS prompts. If code prompts don't appear, simply type " to list all available properties. Or visit the Naïve UI official website to view them.

formItemProps accepts all FormItem and GridItem props except path, span, and label.

ts
/** Form configuration */
const formConfig: FormPro.FormItemConfig[] = [
  {
    name: "name",
    label: "Name",
    props: {
      // Custom attribute
      placeholder: "Please enter your name",
    },
    // Render slots
    slots: {
      // prefix: () => <NEl>😁</NEl>, // Using tsx
      prefix: () => [h(NEl, {}, () => "😁")],
      suffix: () => [h("span", null, "😎")],
    },
    // Form item configuration
    formItemProps: {
      showFeedback: false,
    },
  },
  { name: "age", label: "Age", component: "number" },
];

Dynamic Data

In some cases, such as when options are fetched from an API, you can use computed to return the configuration.

ts
import { type SelectOption } from "naive-ui";

onMounted(async () => {
  loading.value = true;
  options.value = await asyncOptions();
  loading.value = false;
});

/** Default options */
const options = ref<SelectOption[]>([{ label: "Eat", value: 1 }]);

/** Option loading state */
const loading = ref(false);

/** Simulate fetching dynamic options */
const asyncOptions = () => {
  return new Promise<SelectOption[]>((resolve) =>
    setTimeout(
      () =>
        resolve([
          { label: "Eat", value: 1 },
          { label: "Sleep", value: 2 },
          { label: "Play games", value: 3, disabled: true },
        ]),
      2000
    )
  );
};

/** Form configuration */
const formConfig = computed((): FormPro.FormItemConfig[] => [
  {
    name: "hobby",
    label: "Hobby",
    component: "select",
    props: {
      multiple: true, // Enable multiple selection
      loading: loading.value, // Loading state
      options: options.value, // Dynamic options
    },
  },
]);

Dynamic Show/Hide

If you need to show or hide a form item based on certain conditions, use the hidden property.

ts
/** Form data */
const modelValue = ref<FormFields>({
  age: 18,
});

/** Form configuration */
const formConfig = computed((): FormPro.FormItemConfig[] => [
  { name: "age", label: "Age", component: "number" },
  {
    name: "hobby",
    label: "Hobby",
    component: "select",
    hidden: modelValue.value.age <= 18,
    props: {
      multiple: true, // Enable multiple selection
      loading: loading.value, // Loading state
      options: options.value, // Dynamic options
    },
  },
]);

Using Dictionary

If you need to use dictionary data as a data source, add the dict property to the form item configuration and specify the dictionary key. The data source will be automatically fetched from the dictionary.

⚠️ Note

Currently, only select, radio, and checkbox components support dictionaries.
If the options property is set in props, the dict property will be ignored.

ts
/** Form configuration */
const formConfig: FormPro.FormItemConfig[] = [
  {
    name: "sex",
    label: "Gender",
    component: "select",
    dict: "gender", // Use dictionary
  },
];

Using Slots

If you need to use custom slots for rendering, you can do so as follows:

💡 Note

  • The slot name must match the name property in the form-config.
  • Slot content takes priority and will override the component property.
vue
vue
<template>
  <FormPro v-model="modelValue" :form-config="formConfig">
    <!-- Custom slot -->
    <template #name>Custom content</template>
  </FormPro>
</template>

<script lang="ts" setup>
const formConfig: FormPro.FormItemConfig[] = [
  {
    name: "name",
    label: "Name",
    // The component property is ignored when using a slot
    component: "input", 
  },
];
</script>

Custom Component

  • Some users may ask: "What if I want to render my own custom component?"
  • Of course you can!

💡 Note

The component property can accept not only basic component types, but also a function that returns a component, or you can directly pass a component object.

ts
/** Simple component to render msg info */
const MyComponent = defineComponent({
  props: {
    msg: { type: String, default: "Default message" },
  },
  setup(props) {
    return () => h("div", props.msg);
  },
});

/** Form configuration */
const formConfig: FormPro.FormItemConfig[] = [
  {
    name: "msg",
    label: "Message",
    // component: () => <MyComponent msg="hello" />, // Using tsx
    component: () => h(MyComponent, { msg: "hello" }), // Using h function
  },
];

Props

NameTypeRequiredDefaultDescription
v-model or model-valueobjectNoForm binding data
operation-spannumberNo4Operation column width
form-configFormItemConfig[]NoForm item configuration
form-propsFormPropsNosee belowForm properties (except model)
grid-propsGridPropsNosee belowForm layout properties
  • form-props default: { labelPlacement: "left", labelWidth: 80 }
  • grid-props default: { xGap: 16 }

FormItemConfig

NameTypeRequiredDefaultDescription
namestringYesField name
labelstringNoLabel (not shown if not set)
spannumberNo4Grid width
dictstringNoDictionary
hiddenbooleanNofalseWhether hidden
label-messagestringNoTip message
label-reversebooleanNofalseReverse label layout
block-messagestringNoBlock message
componentcomponent TypeNoinputComponent
propscomponent PropsNo{}Component props
slotscomponent SlotsNo{}Component slots
form-item-propsFormItemGi PropsNo{}FormItemGi props

💡 Note

  • label-reverse defaults to false, with the prompt information in front and the label behind; when true, the prompt information is behind and the label is in front.

  • block-message supports both Component and () => VNode types. This configuration is invalid in TablePro for aesthetic reasons, please use label-message instead

  • form-item-props excludes path, label, and span properties.

Component Types

Supported component types:

  • input Input
  • textarea Textarea
  • number Number input
  • password Password input
  • select Select
  • radio Radio group
  • radio-button Radio button group
  • checkbox Checkbox group
  • date Date picker
  • time Time picker
  • switch Switch
  • tree-select Tree select
  • color-picker Color picker
  • slider Slider
  • text Plain text
  • Component Custom component
  • () => VNode Custom component

Component Props and Slots

ComponentPropsSlots
input textarea passwordInput PropsInput Slots
selectSelect PropsSelect Slots
radio radio-buttonRadioGroup Propsundefined
checkboxCheckbox PropsCheckbox Slots
dateDatePicker PropsDatePicker Slots
timeTimePicker PropsTimePicker Slots
switchSwitch PropsSwitch Slots
tree-selectTreeSelect PropsTreeSelect Slots
color-pickerColorPicker PropsColorPicker Slots
sliderSlider PropsSlider Slots
textText PropsText Slots

Slots

NameParamsDescription
operation()Operation area buttons
[name]()Form item slot

Expose

NameTypeDescription
validate() => Promise<void>Trigger validation
reset() => voidReset form

Contributors

Changelog

Released under the MIT License