schema
The schema
prop is the only required prop. It is a Zod schema, and it must be a z.object()
.
If you only pass the schema
to the Form
, then the form will be rendered with
the default components. These are not really the prettiest, as the default
components are intended to be replaced with your own components.
components
The above leads us nicely into the components
. The components
prop is an object
which defines a mapping from a component type to a component definition. The component type is
one of the following:
string
-z.string()
number
-z.number()
enum
-z.enum()
boolean
-z.boolean()
object
-z.object()
array
-z.array()
multiChoice
-z.array(z.enum())
date
-z.date()
Whenever the Form
component encounters a schema of the given type, it will render the
component definition that is mapped to that type. If it doesn't find a component definition,
it will render the default.
How to create a component definition
A component definition is a React component which takes the appropriate props for its type.
Let's say I want to create a component definition for the string
type. To do so, I would need to create
a component such as the one below:
import { IStringDefaultProps } from '@zodform/core';
function CustomString(props: IStringDefaultProps) {
// markup...
}
All component types have a corresponding interface which defines the props that are passed to
the component definition. All those interfaces can be imported from @zodform/core
, and are as follows:
string
-IStringDefaultProps
number
-INumberDefaultProps
enum
-IEnumDefaultProps
boolean
-IBooleanDefaultProps
object
-IObjectDefaultProps
array
-IArrayDefaultProps
multiChoice
-IMultiChoiceDefaultProps
date
-IDateDefaultProps
Once you have created your component definition, you can add it to a components
object
and pass that object to the Form
component:
import { Form } from '@zodform/core';
import { CustomString } from './custom-string';
const schema = z.object({
name: z.string()
});
const components = {
string: CustomString
} as const;
function MyForm() {
return <Form schema={schema} components={components} />;
}
uiSchema
Since the UI requirements of a form component cannot be satisfied by a Zod schema alone, we need to introduce an additional concept: the UI schema. This is a schema which matches the structure of the Zod schema, but it is used for defining UI related properties.
When talking about the UI schema, it is important to keep in mind the two categories of properties that exist:
- Leaf properties - these are properties which render a single input type. All but the object and array are leaf properties
- Compound properties - these are properties which contain other properties. The object and array are compound properties
Base properties
The base properties are shared by all leaf properties. They are as follows:
label
- the label of the componentComponent
- component which overrides the component definition for this typeautoFocus
- whether the component should be focused when the form is renderedcond
- a function which returns a boolean. If the function returnsfalse
, the component will not be rendereddescription
- a description of the component. This will override the schema description, if any
Object properties
Since the object component is tasked with rendering other components, its UI schema needs to allow for customizing the UI of its children, too. So for an object schema like this:
import { z } from 'zod';
const schema = z.object({
person: z.object({
name: z.string(),
age: z.number()
})
});
The UI schema would contain the following properties:
name
- the UI schema for a string componentage
- the UI schema for a number componentui
- the UI schema for the object component itselftitle
- the title of the object componentComponent
- component which overrides the component definition for this propertyLayout
- a component which establishes how the children of the object are rendered. This is useful when you want to render the children in a row, for example, but you don't want to override the component definition for the entire object. (including its title, etc.) See example (opens in a new tab)cond
- a function which returns a boolean. If the function returnsfalse
, the component will not be rendered
Array properties
The array component is also tasked with rendering other components, though these components do not have a name. The array is limited to rendering a single type of component, so the UI schema for an array needs to allow defining the UI for its children's type.
So for an array schema like this:
import { z } from 'zod';
const schema = z.object({
fruits: z.array(z.string())
});
The UI schema would contain the following properties:
title
- same as the objectdescription
- same as the objectcond
- same as the objectelement
- the UI schema for the child type. In this case it is a string, so it would be the same as the base properties