Usage
Use a radio button group only when the options are predefined and there are at least 2 and at most 3 options.
The RadioButtonGroup
component behaves similar to an input component since it is a radio group under the hood. It fills the container and must be wrapped in a Field
component for it to recieve form validation errors.
Note: It's recommended to frame the component as a yes/no question.
Bad ❌
const labels = ['Australia', 'International'];const [index, setIndex] = useState(0);return ( <Field label="Where is your employee located?"> <RadioButtonGroup onChange={setIndex} value={index} options={labels.map((label, value) => ({ label, value }))} /> </Field>);
Good ✅
const labels = ['Yes', 'No'];const [index, setIndex] = useState(0);return ( <Field label="Is your employee located in Australia?"> <RadioButtonGroup onChange={setIndex} value={index} options={labels.map((label, value) => ({ label, value }))} /> </Field>);
Recipes
Toggle between required form sections and field validation based on user selection.
const addressTypeEnum = createTypedEnum({ australian: 'Yes', international: 'No',});const formSchema = field.object( { firstName: field.text({ validate: validate((value) => { validate.required(value); return value; }), }), lastName: field.text({ validate: validate((value) => { validate.required(value); return value; }), }), addressType: field.select<SelectFieldType<typeof addressTypeEnum>>()({ validate: validate((value) => { validate.required(value, 'Location'); return value; }), }), australianAddress: field.object({ street: field.text(), city: field.text(), state: field.text(), postCode: field.text(), }), internationalAddress: field.object({ street: field.text(), city: field.text(), }), }, { validate: { australianAddress: { street: validate.object((value, objectValue) => { if (objectValue.addressType === 'australian') { validate.required(value); } return value; }), city: validate.object((value, objectValue) => { if (objectValue.addressType === 'australian') { validate.required(value); } return value; }), state: validate.object((value, objectValue) => { if (objectValue.addressType === 'australian') { validate.required(value); } return value; }), postCode: validate.object((value, objectValue) => { if (objectValue.addressType === 'australian') { validate.required(value); } return value; }), }, internationalAddress: { street: validate.object((value, objectValue) => { if (objectValue.addressType === 'international') { validate.required(value); } return value; }), city: validate.object((value, objectValue) => { if (objectValue.addressType === 'international') { validate.required(value); } return value; }), }, }, });const Form = () => { const form = useForm(formSchema); const handleSubmit = useSubmit(form, (value) => { alert('form submitted'); }); return ( <Stack as="form" gap="large" onSubmit={handleSubmit}> <FieldStack> <Field label="First name" invalidMessage={form.fields.firstName.props.invalidMessage} > <TextInput {...form.fields.firstName.props} /> </Field> <Field label="Last name" invalidMessage={form.fields.lastName.props.invalidMessage} > <TextInput {...form.fields.lastName.props} /> </Field> <Box width={300}> <Field label="Are you located in Australia?" invalidMessage={form.fields.addressType.props.invalidMessage} > <RadioButtonGroup options={addressTypeEnum.selectOptions} value={form.fields.addressType.props.value} onChange={(value) => { form.fields.addressType.setState((state) => ({ ...state, value: addressTypeEnum.validateValue(value), })); }} /> </Field> </Box> {form.value.addressType === 'australian' && ( <React.Fragment> <Heading level="7">Australian address</Heading> <Field label="Street" invalidMessage={ form.fields.australianAddress.fields.street.props.invalidMessage } > <TextInput {...form.fields.australianAddress.fields.street.props} /> </Field> <Field label="City" invalidMessage={ form.fields.australianAddress.fields.city.props.invalidMessage } > <TextInput {...form.fields.australianAddress.fields.city.props} /> </Field> <Field label="State" invalidMessage={ form.fields.australianAddress.fields.state.props.invalidMessage } > <TextInput {...form.fields.australianAddress.fields.state.props} /> </Field> <Field label="Post code" invalidMessage={ form.fields.australianAddress.fields.postCode.props .invalidMessage } > <TextInput {...form.fields.australianAddress.fields.postCode.props} /> </Field> </React.Fragment> )} {form.value.addressType === 'international' && ( <React.Fragment> <Heading level="7">International address</Heading> <Field label="Street" invalidMessage={ form.fields.internationalAddress.fields.street.props .invalidMessage } > <TextInput {...form.fields.internationalAddress.fields.street.props} /> </Field> <Field label="City" invalidMessage={ form.fields.internationalAddress.fields.city.props .invalidMessage } > <TextInput {...form.fields.internationalAddress.fields.city.props} /> </Field> </React.Fragment> )} <Button type="submit" label="Submit" block /> </FieldStack> </Stack> );};return <Form />;
Yes/no/maybe(as text) option
const feedbackTypeEnum = createTypedEnum({ yes: 'Yes', no: 'No', maybe: 'Maybe',});const formSchema = field.object( { recommendation: field.select<SelectFieldType<typeof feedbackTypeEnum>>()({ validate: validate((value) => { validate.required(value, 'Location'); return value; }), }), feedback: field.text(), }, { validate: { feedback: validate.object((value, objectValue) => { if (objectValue.recommendation === 'maybe') { validate.required(value, "Feedback"); } return value; }) }, });const Form = () => { const form = useForm(formSchema); const handleSubmit = useSubmit(form, (value) => { alert('form submitted'); }); return ( <Stack as="form" gap="large" onSubmit={handleSubmit}> <FieldStack> <Box width={300}> <Field label="Would you recommend this product to your friends and family?" invalidMessage={form.fields.recommendation.props.invalidMessage} > <RadioButtonGroup options={feedbackTypeEnum.selectOptions} value={form.fields.recommendation.props.value} onChange={(value) => { form.fields.recommendation.setState((state) => ({ ...state, value: feedbackTypeEnum.validateValue(value), })); }} /> </Field> </Box> {form.value.recommendation === 'maybe' && ( <Field label="Feedback" description="What can we do to improve our product?" invalidMessage={ form.fields.feedback.props.invalidMessage } > <TextInput {...form.fields.feedback.props} /> </Field> )} <Button type="submit" label="Submit" block /> </FieldStack> </Stack> );};return <Form />;