Agriculture Design System
Beta
Design System for the Export Service

Conditionally revealed form content

Revealing additional form questions and help content after a user selects an option can reduce the amount of content a user must read when completing complex forms.

Do

  • limit what is revealed to a single set of related questions or information that does not require its own submit action
  • reveal the related set of questions under the initial input or controls
  • use another page if there are multiple related questions that need a submit action
  • only use with vertically stacked checkboxes or radios.

Don’t

  • reveal a complete form with submit action
  • use with horizontally stacked checkboxes or radios
  • reveal anything other than questions or supporting information relating directly to the initial option selected by the user.

Radio

When a user selects a specific option from a Radio control group, additional questions or helpful information relevant to their selection can be revealed. Revealing content after a selection is made ensures a user will only see content that is relevant to them.

If there a large number of items, use Select instead.

Open in Playroom, opens in a new tab
() => {
	const [value, setValue] = React.useState();
	const handlerForKey = React.useCallback((key) => () => setValue(key), []);
	const isChecked = (key) => key === value;

	return (
		<FormStack>
			<ControlGroup label="Preferred contact method" required block>
				<Radio checked={isChecked('email')} onChange={handlerForKey('email')}>
					Email
				</Radio>
				<Radio checked={isChecked('phone')} onChange={handlerForKey('phone')}>
					Phone
				</Radio>
				<Radio
					checked={isChecked('textMessage')}
					onChange={handlerForKey('textMessage')}
				>
					Text message
				</Radio>
			</ControlGroup>

			<ConditionalFieldContainer visible={isChecked('email')}>
				<TextInput type="email" label="Email address" required />
			</ConditionalFieldContainer>
			<ConditionalFieldContainer visible={isChecked('phone')}>
				<TextInput label="Phone number" inputMode="numeric" required />
			</ConditionalFieldContainer>
			<ConditionalFieldContainer visible={isChecked('textMessage')}>
				<TextInput label="Mobile phone number" inputMode="numeric" required />
			</ConditionalFieldContainer>
		</FormStack>
	);
};

Checkbox

When a user selects a particular Checkbox, you can reveal additional questions or provide helpful information that is relevant to the selection after the Checkbox control group. Revealing content after a selection is made ensures a user will only see content that is relevant to them.

() => {
	const [value, setValue] = React.useState([]);
	const handlerForKey = React.useCallback(
		(key) => () =>
			setValue((value) =>
				value.includes(key) ? value.filter((v) => v !== key) : [...value, key]
			),
		[]
	);
	const isChecked = (key) => value.includes(key);

	return (
		<FormStack>
			<ControlGroup label="How would you like to be contacted?" required block>
				<Checkbox
					checked={isChecked('email')}
					onChange={handlerForKey('email')}
				>
					Email
				</Checkbox>
				<Checkbox
					checked={isChecked('phone')}
					onChange={handlerForKey('phone')}
				>
					Phone
				</Checkbox>
				<Checkbox
					checked={isChecked('textMessage')}
					onChange={handlerForKey('textMessage')}
				>
					Text message
				</Checkbox>
			</ControlGroup>

			<ConditionalFieldContainer visible={value.length}>
				{isChecked('email') && (
					<TextInput type="email" label="Email address" required />
				)}
				{isChecked('phone') && (
					<TextInput inputMode="numeric" label="Phone number" required />
				)}
				{isChecked('textMessage') && (
					<TextInput inputMode="numeric" label="Mobile phone number" required />
				)}
			</ConditionalFieldContainer>
		</FormStack>
	);
};

Select

When a user selects a particular option from a Select dropdown, additional questions or helpful information relevant to their selection can be revealed. This ensures that the user only sees content that is pertinent to their choice.

If there a small number of items, use Radio instead.

() => {
	const [value, setValue] = React.useState('');
	const handlerForKey = React.useCallback((e) => setValue(e.target.value), []);
	const isChecked = (key) => value === key;

	return (
		<FormStack>
			<Select
				placeholder="Please select"
				label="How would you like to be contacted?"
				onChange={handlerForKey}
				options={[
					{ value: 'post', label: 'Post' },
					{ value: 'textMessage', label: 'Text message' },
					{ value: 'email', label: 'E mail' },
				]}
				required
				value={value}
			/>

			<ConditionalFieldContainer visible={isChecked('post')}>
				<H2>Address</H2>
				<TextInput
					inputMode="text"
					label="Street address"
					maxWidth="xl"
					required
					type="text"
				/>
				<TextInput
					inputMode="text"
					label="Suburb, town or city"
					maxWidth="lg"
					required
					type="text"
				/>
				<Select
					label="State or territory"
					maxWidth="sm"
					options={[
						{ label: 'ACT', value: 'act' },
						{ label: 'NSW', value: 'nsw' },
						{ label: 'NT', value: 'nt' },
						{ label: 'QLD', value: 'qld' },
						{ label: 'SA', value: 'sa' },
						{ label: 'TAS', value: 'tas' },
						{ label: 'VIC', value: 'vic' },
						{ label: 'WA', value: 'wa' },
					]}
					required
				/>
				<TextInput
					inputMode="numeric"
					label="Post code"
					required
					maxWidth="sm"
				/>
			</ConditionalFieldContainer>

			<ConditionalFieldContainer visible={isChecked('textMessage')}>
				<TextInput inputMode="text" label="Mobile phone number" required />
			</ConditionalFieldContainer>

			<ConditionalFieldContainer visible={isChecked('email')}>
				<TextInput type="email" label="Email address" required />
			</ConditionalFieldContainer>
		</FormStack>
	);
};

Invalid

When a conditionally revealed question is invalid, include an error message on the invalid field that is clearly related to the initial question.

() => {
	const [value, setValue] = React.useState('email');
	const handlerForKey = React.useCallback((key) => () => setValue(key), []);
	const isChecked = (key) => key === value;

	return (
		<FormStack>
			<ControlGroup label="Preferred contact method" required block>
				<Radio checked={isChecked('email')} onChange={handlerForKey('email')}>
					Email
				</Radio>
				<Radio checked={isChecked('phone')} onChange={handlerForKey('phone')}>
					Phone
				</Radio>
				<Radio
					checked={isChecked('textMessage')}
					onChange={handlerForKey('textMessage')}
				>
					Text message
				</Radio>
			</ControlGroup>

			<ConditionalFieldContainer visible={isChecked('email')}>
				<TextInput
					type="email"
					label="Email address"
					required
					invalid
					message="Enter a email address"
				/>
			</ConditionalFieldContainer>
			<ConditionalFieldContainer visible={isChecked('phone')}>
				<TextInput
					label="Phone number"
					inputMode="numeric"
					required
					invalid
					message="Enter a phone number"
				/>
			</ConditionalFieldContainer>
			<ConditionalFieldContainer visible={isChecked('textMessage')}>
				<TextInput
					label="Mobile phone number"
					inputMode="numeric"
					required
					invalid
					message="Enter a mobile phone number"
				/>
			</ConditionalFieldContainer>
		</FormStack>
	);
};

Research

March 2025

Before March 2025, conditional form elements were revealed immediately after their parent radio or checkbox, and inside their control group.

This pattern worked well for sighted users who could see the relationship and context between the control and conditionally revealed form elements. However, we observed screen reader users becoming disoriented when they encountered additional form elements between items in the control group. In response, we adjusted our guidance to position the additional questions immediately after the control group.

This updated pattern has been tested in two rounds of usability studies. We have observed no issues since the change.

  • Conditional field container A standardised pattern for conditionally hiding and revealing the amount of content a user views in a form.