Demos
Without Form.Handler
<Form.Section data={{ myField: 'Value', }} onChange={console.log} > <Field.String path="/myField" /> </Form.Section>
With a nested path
This lets you reuse the same section of fields in multiple places in your forms.
const MyNameSection = (props: SectionProps) => { return ( <Form.Section {...props}> <Form.Card> <Field.Name.First path="/firstName" /> <Field.Name.Last path="/lastName" /> </Form.Card> </Form.Section> ) } render( <Form.Handler onSubmit={async (data) => console.log('onSubmit', data)} defaultData={{ nestedPath: { firstName: 'Nora', lastName: 'Mørk', }, }} > <MyNameSection path="/nestedPath" /> <Form.SubmitButton variant="send" /> </Form.Handler>, )
With a Edit and View container
This example uses the Form.Section.EditContainer and Form.Section.ViewContainer containers with the default variant="outline".
Show errors on the whole section
When a field in the section has an error and the section has containerMode set to auto (default), the whole section will switch to edit mode. The errors will be shown when validateInitially is set to true.
Using variant="basic"
Using variant="basic" will render the view and edit container without the additional Card outline.
Overwrite properties
Overwriting properties makes it very flexible to reuse the same section of fields in multiple places in your forms.
const MyNameSection = (props) => { return ( <Form.Section {...props}> <Form.Card> <Field.Composition width="large"> <Field.Name.First path="/firstName" /> <Field.Name.Last path="/lastName" required minLength={10} /> </Field.Composition> </Form.Card> </Form.Section> ) } render( <Form.Handler onSubmit={async (data) => console.log('onSubmit', data)} defaultData={{ nestedPath: { firstName: '', lastName: 'M', }, }} > <MyNameSection path="/nestedPath" overwriteProps={{ firstName: { required: true, label: 'Custom', }, lastName: { required: false, minLength: 2, }, }} /> <Form.SubmitButton variant="send" /> </Form.Handler>, )
Schema support
This feature lets you extend the requirements of the fields in the section with a JSON Schema.
const MyNameSection = (props: SectionProps) => { return ( <Form.Section {...props}> <Form.Card> <Field.Composition width="large"> <Field.Name.First path="/firstName" /> <Field.Name.Last path="/lastName" required minLength={10} /> </Field.Composition> </Form.Card> </Form.Section> ) } const mySchema: JSONSchema = { type: 'object', properties: { nestedPath: { type: 'object', properties: { firstName: { type: 'string', minLength: 3, }, lastName: { type: 'string', minLength: 2, }, }, required: ['firstName', 'lastName'], }, }, } const ajv = makeAjvInstance() render( <Form.Handler onSubmit={async (data) => console.log('onSubmit', data)} schema={mySchema} ajvInstance={ajv} defaultData={{ nestedPath: { firstName: '', lastName: 'M', }, }} > <MyNameSection path="/nestedPath" /> <Form.SubmitButton variant="send" /> </Form.Handler>, )
Required support
You can easily make a section of fields required by setting the required property on the section itself.
const MyNameSection = (props: SectionProps) => { return ( <Form.Section {...props}> <Form.Card> <Field.Composition width="large"> <Field.Name.First path="/firstName" /> <Field.Name.Last path="/lastName" /> </Field.Composition> </Form.Card> </Form.Section> ) } const schema: JSONSchema = { type: 'object', required: ['myRequiredSection'], } const ajv = makeAjvInstance() render( <Flex.Stack> <Form.Handler onSubmit={async (data) => console.log('onSubmit', data)}> <MyNameSection required /> <Form.SubmitButton variant="send" /> </Form.Handler> <Form.Handler onSubmit={async (data) => console.log('onSubmit', data)} schema={schema} ajvInstance={ajv} > <MyNameSection path="/myRequiredSection" /> <Form.SubmitButton variant="send" /> </Form.Handler> </Flex.Stack>, )
Nested sections
You can nest sections inside each other.
render( <Form.Handler onSubmit={async (data) => console.log('onSubmit', data)} defaultData={{ nestedPath: { name: { first: 'Nora', last: 'Mørk', }, address: { street: 'Strøget', nr: '', }, }, }} > <MySection path="/nestedPath" required /> <Form.SubmitButton variant="send" /> </Form.Handler>, ) function MySection(props: SectionProps) { return ( <Form.Section {...props}> <Form.Card> <MyNameSection path="/name" /> <MyAddressSection path="/address" /> <MyValueSection /> </Form.Card> </Form.Section> ) } function MyNameSection(props: SectionProps) { return ( <Form.Section {...props}> <Field.Composition width="large"> <Field.Name.First path="/first" /> <Field.Name.Last path="/last" /> </Field.Composition> </Form.Section> ) } function MyAddressSection(props: SectionProps) { return ( <Form.Section {...props}> <Field.Composition width="large"> <Field.String label="Gateadresse" path="/street" width="stretch" /> <Field.String label="Nr." path="/nr" width="small" /> </Field.Composition> </Form.Section> ) } function MyValueSection(props: SectionProps) { return ( <Form.Section {...props}> <Value.SummaryList> <Form.Section path="/name"> <Value.Composition gap="small"> <Value.Name.First path="/first" /> <Value.Name.Last path="/last" /> </Value.Composition> </Form.Section> <Form.Section path="/address"> <Value.Composition gap="small"> <Value.String label="Gateadresse" path="/street" /> <Value.String label="Nr." path="/nr" placeholder="–" /> </Value.Composition> </Form.Section> </Value.SummaryList> </Form.Section> ) }
With Visibility logic
The Form.Visibility component lets you show or hide parts of your form based on the data given in the section itself.
const MySection = ({ children, ...props }) => { return ( <Form.Section {...props}> <Form.Card> <Field.Boolean label="Are you sure?" variant="buttons" path="/iAmSure" /> <Form.Visibility pathTrue="/iAmSure" animate> <Field.Selection label="Choose" variant="radio" path="/mySelection" > <Field.Option value="less" title="Less" /> <Field.Option value="more" title="More" /> </Field.Selection> <Form.Visibility visibleWhen={{ path: '/mySelection', hasValue: 'more', }} animate > <Field.String label="My String" path="/myString" /> </Form.Visibility> </Form.Visibility> {children} </Form.Card> <Tools.Log /> </Form.Section> ) } render( <Form.Handler onChange={console.log} defaultData={{ nestedPath: { iAmSure: false, mySelection: 'less', myString: 'has a value', }, }} > <MySection path="/nestedPath"> <Form.Visibility visibleWhen={{ path: '/myString', hasValue: (value) => value !== 'has a value', }} animate > <P> Result: <Value.String path="/nestedPath/myString" inline /> </P> </Form.Visibility> </MySection> </Form.Handler>, )