Agriculture Design System
Beta
Design System for the Export Service

Drawer

A drawer is a panel that slides in from the right side of the screen. The Drawer is overlayed on top of the main area of the page to capture the user’s attention while keeping the context of the current task.

View in FigmaView in StorybookView in Github
import { ... } from '@ag.ds-next/react/drawer';
Open in Playroom, opens in a new tab
() => {
	const [isDrawerOpen, openDrawer, closeDrawer] = useTernaryState(false);
	return (
		<React.Fragment>
			<Button onClick={openDrawer}>Open Drawer</Button>
			<Drawer
				isOpen={isDrawerOpen}
				onClose={closeDrawer}
				title="Drawer title"
				actions={
					<ButtonGroup>
						<Button onClick={closeDrawer}>Primary</Button>
						<Button variant="secondary" onClick={closeDrawer}>
							Secondary
						</Button>
						<Button variant="tertiary" onClick={closeDrawer}>
							Tertiary
						</Button>
					</ButtonGroup>
				}
			>
				<Text as="p">Drawer body area.</Text>
			</Drawer>
		</React.Fragment>
	);
};

Do

  • consider using a side action page first – side action pages support more use cases than side drawers
  • only use side drawers for filters, small overflow form actions and related guidance content
  • only use for external (customer-facing) forms if there is a need to maintain some context of the current page, otherwise link to a separate page
  • read the Search filters pattern
  • use a Button group to display actions
  • include a meaningful title - e.g. ‘Filter by’
  • optionally close the Drawer when an action button is pressed
  • use the muted overlay when it is beneficial to retain the user’s context of the underlying page content, especially for sighted users with cognitive disabilities

Don’t

  • use for long forms or any content that is likely to cause a user to scroll vertically or horizontally in the drawer – link to a separate page instead
  • provide navigation or multiple pages inside a drawer
  • remove the ‘Close’ button
  • remove the overlay
  • change default behaviour
  • use the muted overlay because you prefer the lighter appearance

Opening the Drawer

The Drawer can be opened by pressing a button or a link. For example, pressing a ‘Show filter’ button opens a medium Drawer containing filters.

When the Drawer is opened, an overlay is displayed over the main area of the page. This prevents the main area of the page from being interacted with, while still allowing users to maintain their context.

Closing the Drawer

The Drawer can be closed by either:

  1. Pressing the ‘Close’ button
  2. Pressing the ‘Escape’ key
  3. Pressing the overlay
  4. Pressing a button in the actions area (optional)

When closing the Drawer, focus should be returned to the button that opened the Drawer.

Drawer widths

The Drawer comes in the following 2 widths:

  • Medium md (512px) - generally used to display form fields like filters. This width is the minimum required to stack form fields, including date range fields.
  • Large lg (720px) - generally used to display body text like help or guidance content. This width accommodates the Prose component, which has an optimal line length to aid readability.
() => {
	const [isDrawerOpen, openDrawer, closeDrawer] = useTernaryState(false);
	return (
		<React.Fragment>
			<Button onClick={openDrawer}>Open Medium Drawer</Button>
			<Drawer
				isOpen={isDrawerOpen}
				onClose={closeDrawer}
				title="Medium Drawer"
				actions={
					<ButtonGroup>
						<Button onClick={closeDrawer}>Primary</Button>
						<Button variant="secondary" onClick={closeDrawer}>
							Secondary
						</Button>
						<Button variant="tertiary" onClick={closeDrawer}>
							Tertiary
						</Button>
					</ButtonGroup>
				}
			>
				<Select
					label="Example filter"
					placeholder="Please select"
					options={[
						{ value: 'a', label: 'Option A' },
						{ value: 'b', label: 'Option B' },
						{ value: 'c', label: 'Option C' },
					]}
					hideOptionalLabel
					block
				/>
			</Drawer>
		</React.Fragment>
	);
};
() => {
	const [isDrawerOpen, openDrawer, closeDrawer] = useTernaryState(false);
	return (
		<React.Fragment>
			<Button onClick={openDrawer}>Open Large Drawer</Button>
			<Drawer
				isOpen={isDrawerOpen}
				onClose={closeDrawer}
				title="Large Drawer"
				width="lg"
				actions={
					<ButtonGroup>
						<Button onClick={closeDrawer}>Primary</Button>
						<Button variant="secondary" onClick={closeDrawer}>
							Secondary
						</Button>
						<Button variant="tertiary" onClick={closeDrawer}>
							Tertiary
						</Button>
					</ButtonGroup>
				}
			>
				<Prose>
					<p>
						Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
						eiusmod tempor incididunt ut labore et dolore magna aliqua. Tempus
						urna et pharetra pharetra massa massa. Volutpat diam ut venenatis
						tellus in metus vulputate eu. Adipiscing elit duis tristique
						sollicitudin nibh sit amet. Vivamus arcu felis bibendum ut tristique
						et. Et tortor at risus viverra adipiscing at in tellus integer.
						Euismod in pellentesque massa placerat duis ultricies lacus sed.
						Ornare arcu dui vivamus arcu felis bibendum. Sapien pellentesque
						habitant morbi tristique senectus et netus et malesuada. Et tortor
						consequat id porta nibh venenatis. Cras adipiscing enim eu turpis
						egestas pretium aenean. Erat velit scelerisque in dictum non.
						Pretium fusce id velit ut tortor pretium. Eu ultrices vitae auctor
						eu augue ut lectus arcu bibendum. Magna eget est lorem ipsum dolor
						sit.
					</p>

					<p>
						Ut aliquam purus sit amet luctus venenatis lectus magna. Eu
						facilisis sed odio morbi quis commodo odio. Pharetra vel turpis nunc
						eget. Adipiscing commodo elit at imperdiet dui accumsan sit amet
						nulla. Ipsum consequat nisl vel pretium lectus. Malesuada nunc vel
						risus commodo viverra maecenas accumsan lacus vel. Arcu ac tortor
						dignissim convallis. Ipsum suspendisse ultrices gravida dictum fusce
						ut placerat orci nulla. Feugiat sed lectus vestibulum mattis
						ullamcorper. Risus in hendrerit gravida rutrum quisque non.
						Tincidunt nunc pulvinar sapien et ligula. Penatibus et magnis dis
						parturient montes nascetur ridiculus mus. Ultrices tincidunt arcu
						non sodales neque. Duis at consectetur lorem donec.
					</p>

					<p>
						Turpis tincidunt id aliquet risus. Ut lectus arcu bibendum at varius
						vel pharetra. Magna ac placerat vestibulum lectus. Euismod elementum
						nisi quis eleifend quam. Morbi tristique senectus et netus et
						malesuada. Justo laoreet sit amet cursus sit. Et malesuada fames ac
						turpis egestas sed. Eu non diam phasellus vestibulum lorem sed risus
						ultricies. Quis imperdiet massa tincidunt nunc. Ornare lectus sit
						amet est placerat in egestas. Sed viverra ipsum nunc aliquet
						bibendum enim facilisis gravida neque. Lacinia quis vel eros donec
						ac. Vitae sapien pellentesque habitant morbi. Donec et odio
						pellentesque diam volutpat commodo sed egestas egestas. Vulputate
						sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum.
						Quam vulputate dignissim suspendisse in est ante in nibh. Justo nec
						ultrices dui sapien eget mi proin. Aliquet nibh praesent tristique
						magna sit amet.
					</p>
					<p>
						Laoreet suspendisse interdum consectetur libero. Nulla pellentesque
						dignissim enim sit amet venenatis urna cursus eget. Elit sed
						vulputate mi sit amet mauris commodo quis imperdiet. Nisl suscipit
						adipiscing bibendum est ultricies integer quis. Rutrum tellus
						pellentesque eu tincidunt tortor aliquam nulla. Malesuada fames ac
						turpis egestas sed tempus urna et. Ipsum dolor sit amet consectetur
						adipiscing elit duis tristique. Euismod elementum nisi quis eleifend
						quam. Vulputate mi sit amet mauris commodo quis imperdiet massa. Sit
						amet porttitor eget dolor. Enim lobortis scelerisque fermentum dui
						faucibus. Dapibus ultrices in iaculis nunc sed augue lacus. Nulla
						porttitor massa id neque aliquam vestibulum. Netus et malesuada
						fames ac turpis egestas integer eget aliquet. Proin nibh nisl
						condimentum id. Duis at tellus at urna condimentum mattis. Tellus
						molestie nunc non blandit massa. At erat pellentesque adipiscing
						commodo elit at imperdiet dui.
					</p>
					<p>
						Imperdiet proin fermentum leo vel orci porta non. Odio morbi quis
						commodo odio aenean sed adipiscing diam donec. Cursus in hac
						habitasse platea dictumst quisque sagittis. Blandit aliquam etiam
						erat velit scelerisque in dictum. Ridiculus mus mauris vitae
						ultricies. Interdum velit laoreet id donec ultrices. Est
						pellentesque elit ullamcorper dignissim cras tincidunt lobortis. Sed
						nisi lacus sed viverra tellus in. Vel elit scelerisque mauris
						pellentesque pulvinar pellentesque habitant morbi. Vitae congue
						mauris rhoncus aenean. Ut porttitor leo a diam sollicitudin tempor.
						Tincidunt arcu non sodales neque sodales ut etiam. At elementum eu
						facilisis sed. Euismod in pellentesque massa placerat duis. In arcu
						cursus euismod quis viverra nibh cras pulvinar. Neque egestas congue
						quisque egestas diam in. Sem fringilla ut morbi tincidunt augue
						interdum. Sit amet tellus cras adipiscing enim.
					</p>

					<p>
						Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
						eiusmod tempor incididunt ut labore et dolore magna aliqua. Tempus
						urna et pharetra pharetra massa massa. Volutpat diam ut venenatis
						tellus in metus vulputate eu. Adipiscing elit duis tristique
						sollicitudin nibh sit amet. Vivamus arcu felis bibendum ut tristique
						et. Et tortor at risus viverra adipiscing at in tellus integer.
						Euismod in pellentesque massa placerat duis ultricies lacus sed.
						Ornare arcu dui vivamus arcu felis bibendum. Sapien pellentesque
						habitant morbi tristique senectus et netus et malesuada. Et tortor
						consequat id porta nibh venenatis. Cras adipiscing enim eu turpis
						egestas pretium aenean. Erat velit scelerisque in dictum non.
						Pretium fusce id velit ut tortor pretium. Eu ultrices vitae auctor
						eu augue ut lectus arcu bibendum. Magna eget est lorem ipsum dolor
						sit.
					</p>

					<p>
						Ut aliquam purus sit amet luctus venenatis lectus magna. Eu
						facilisis sed odio morbi quis commodo odio. Pharetra vel turpis nunc
						eget. Adipiscing commodo elit at imperdiet dui accumsan sit amet
						nulla. Ipsum consequat nisl vel pretium lectus. Malesuada nunc vel
						risus commodo viverra maecenas accumsan lacus vel. Arcu ac tortor
						dignissim convallis. Ipsum suspendisse ultrices gravida dictum fusce
						ut placerat orci nulla. Feugiat sed lectus vestibulum mattis
						ullamcorper. Risus in hendrerit gravida rutrum quisque non.
						Tincidunt nunc pulvinar sapien et ligula. Penatibus et magnis dis
						parturient montes nascetur ridiculus mus. Ultrices tincidunt arcu
						non sodales neque. Duis at consectetur lorem donec.
					</p>

					<p>
						Turpis tincidunt id aliquet risus. Ut lectus arcu bibendum at varius
						vel pharetra. Magna ac placerat vestibulum lectus. Euismod elementum
						nisi quis eleifend quam. Morbi tristique senectus et netus et
						malesuada. Justo laoreet sit amet cursus sit. Et malesuada fames ac
						turpis egestas sed. Eu non diam phasellus vestibulum lorem sed risus
						ultricies. Quis imperdiet massa tincidunt nunc. Ornare lectus sit
						amet est placerat in egestas. Sed viverra ipsum nunc aliquet
						bibendum enim facilisis gravida neque. Lacinia quis vel eros donec
						ac. Vitae sapien pellentesque habitant morbi. Donec et odio
						pellentesque diam volutpat commodo sed egestas egestas. Vulputate
						sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum.
						Quam vulputate dignissim suspendisse in est ante in nibh. Justo nec
						ultrices dui sapien eget mi proin. Aliquet nibh praesent tristique
						magna sit amet.
					</p>
					<p>
						Laoreet suspendisse interdum consectetur libero. Nulla pellentesque
						dignissim enim sit amet venenatis urna cursus eget. Elit sed
						vulputate mi sit amet mauris commodo quis imperdiet. Nisl suscipit
						adipiscing bibendum est ultricies integer quis. Rutrum tellus
						pellentesque eu tincidunt tortor aliquam nulla. Malesuada fames ac
						turpis egestas sed tempus urna et. Ipsum dolor sit amet consectetur
						adipiscing elit duis tristique. Euismod elementum nisi quis eleifend
						quam. Vulputate mi sit amet mauris commodo quis imperdiet massa. Sit
						amet porttitor eget dolor. Enim lobortis scelerisque fermentum dui
						faucibus. Dapibus ultrices in iaculis nunc sed augue lacus. Nulla
						porttitor massa id neque aliquam vestibulum. Netus et malesuada
						fames ac turpis egestas integer eget aliquet. Proin nibh nisl
						condimentum id. Duis at tellus at urna condimentum mattis. Tellus
						molestie nunc non blandit massa. At erat pellentesque adipiscing
						commodo elit at imperdiet dui.
					</p>
					<p>
						Imperdiet proin fermentum leo vel orci porta non. Odio morbi quis
						commodo odio aenean sed adipiscing diam donec. Cursus in hac
						habitasse platea dictumst quisque sagittis. Blandit aliquam etiam
						erat velit scelerisque in dictum. Ridiculus mus mauris vitae
						ultricies. Interdum velit laoreet id donec ultrices. Est
						pellentesque elit ullamcorper dignissim cras tincidunt lobortis. Sed
						nisi lacus sed viverra tellus in. Vel elit scelerisque mauris
						pellentesque pulvinar pellentesque habitant morbi. Vitae congue
						mauris rhoncus aenean. Ut porttitor leo a diam sollicitudin tempor.
						Tincidunt arcu non sodales neque sodales ut etiam. At elementum eu
						facilisis sed. Euismod in pellentesque massa placerat duis. In arcu
						cursus euismod quis viverra nibh cras pulvinar. Neque egestas congue
						quisque egestas diam in. Sem fringilla ut morbi tincidunt augue
						interdum. Sit amet tellus cras adipiscing enim.
					</p>
				</Prose>
			</Drawer>
		</React.Fragment>
	);
};

Drawer with muted overlay

By default, Drawer’s overlay defaults to 80% opacity, however, by adding mutedOverlay={true}, the opacity can be reduced to 30%. This muted version allows sighted users with cognitive disabilites to more easily retain the context of the main page content while interacting with the drawer content.

() => {
	const [isDrawerOpen, openDrawer, closeDrawer] = useTernaryState(false);
	return (
		<React.Fragment>
			<Button onClick={openDrawer}>Open Muted Drawer</Button>
			<Drawer
				isOpen={isDrawerOpen}
				onClose={closeDrawer}
				mutedOverlay={true}
				title="Drawer title"
				actions={
					<ButtonGroup>
						<Button onClick={closeDrawer}>Primary</Button>
						<Button variant="secondary" onClick={closeDrawer}>
							Secondary
						</Button>
						<Button variant="tertiary" onClick={closeDrawer}>
							Tertiary
						</Button>
					</ButtonGroup>
				}
			>
				<Text as="p">
					Notice that the main page content is much easier to read.
				</Text>
			</Drawer>
		</React.Fragment>
	);
};

Focus custom element on close

When a drawer closes, focus is returned to the element that opened it. You can override this behaviour by passing an element to the elementToFocusOnClose prop. This can be used in situations, for example, when an action performed in the drawer causes an error, setting the main page in an error state, and requiring the user’s focus to be returned to the alert instead.

() => {
	const sectionAlertContainerRef = React.useRef(null);
	const [error, setError] = React.useState('');
	const [isDrawerOpen, openDrawer, closeDrawer] = useTernaryState(false);

	const openDrawerAndClearError = () => {
		openDrawer();
		setError('');
	};

	const closeWithError = () => {
		closeDrawer();
		setError('We were unable to perform the action, please try again later.');
	};

	return (
		<Stack gap={2}>
			<Box css={error ? undefined : { display: 'none' }}>
				<SectionAlert
					focusRingFor="all"
					ref={sectionAlertContainerRef}
					tabIndex={-1}
					title="Something went wrong"
					tone="error"
				>
					<Text as="p">{error}</Text>
				</SectionAlert>
			</Box>

			<Button alignSelf="start" onClick={openDrawerAndClearError}>
				Open Drawer
			</Button>

			<Drawer
				actions={
					<ButtonGroup>
						<Button onClick={closeWithError}>Close with error</Button>
						<Button variant="secondary" onClick={closeDrawer}>
							Close with no error
						</Button>
					</ButtonGroup>
				}
				elementToFocusOnClose={
					error ? sectionAlertContainerRef.current : undefined
				}
				isOpen={isDrawerOpen}
				onClose={closeDrawer}
				title="Drawer title"
			>
				<Text as="p">
					When pressing 'Close with error', an error alert will be rendered and
					focused.
				</Text>
			</Drawer>
		</Stack>
	);
};

Using a form in the drawer

To create a fully accessible form within a drawer, we must do two things:

  1. Add an id to the <form>.
  2. Pass that id to the primary Button's form prop along with type="submit".

This will allow keyboard users to submit the form by pressing "enter" on the form inputs.

() => {
	const formRef = React.useRef(null);
	const [isDrawerOpen, openDrawer, closeDrawer] = useTernaryState(false);
	const onSubmitForm = (event) => {
		event.preventDefault();

		const formData = Object.fromEntries(new FormData(formRef.current));
		console.log('Form submitted with values:', formData);

		closeDrawer();
	};

	return (
		<React.Fragment>
			<Button onClick={openDrawer}>Open Drawer</Button>

			<Drawer
				actions={
					<ButtonGroup>
						<Button type="submit" form="form-id" onClick={onSubmitForm}>
							Submit
						</Button>

						<Button variant="tertiary" onClick={closeDrawer}>
							Cancel
						</Button>
					</ButtonGroup>
				}
				isOpen={isDrawerOpen}
				onClose={closeDrawer}
				title="Example form"
			>
				<form id="form-id" ref={formRef}>
					<FormStack>
						<TextInput label="Example text input" name="textInput" />

						<TextInput
							label="Example text input"
							name="numberInput"
							type="number"
						/>
					</FormStack>
				</form>
			</Drawer>
		</React.Fragment>
	);
};
  • Modal A modal is a dialog box that appears above the parent page and provides advance notice of a destructive action and consequence. They tell users a decision is needed.
  • Search filters Search filters help users find what they’re looking for by displaying options that meet specified criteria.