SidePanel

Beta

SidePanels are vertical containers used to display additional information that supports the main content area or to edit specific content within the page.

installyarn add @clayui/core
versionNPM Version
useimport {SidePanel} from '@clayui/core';

Example

import {SidePanel, Provider} from '@clayui/core';
import Button from '@clayui/button';
import React from 'react';

import '@clayui/css/lib/css/atlas.css';

export default function App() {
	const [open, setOpen] = React.useState(false);

	const ref = React.useRef();

	return (
		<Provider spritemap="/public/icons.svg">
			<div className="p-4" ref={ref} style={{minHeight: '100vh'}}>
				<Button
					aria-controls="sidepanel-example"
					aria-pressed={open}
					onClick={() => setOpen(!open)}
				>
					Open
				</Button>

				<SidePanel
					containerRef={ref}
					id="sidepanel-example"
					onOpenChange={setOpen}
					open={open}
				>
					<SidePanel.Header>
						<SidePanel.Title>Title</SidePanel.Title>
					</SidePanel.Header>
					<SidePanel.Body>Body</SidePanel.Body>
					<SidePanel.Footer>
						<Button.Group spaced>
							<Button>Primary</Button>
							<Button displayType="secondary">Secondary</Button>
						</Button.Group>
					</SidePanel.Footer>
				</SidePanel>
			</div>
		</Provider>
	);
}

Introduction

The SidePanel component provides a more easy and quick way for the users to consult or edit information without the need for deeper navigation.

SidePanels can anchor to the left or right side of the screen. They can be collapsible or triggered by a button or a link. When activated, the SidePanel opens and the content of the page is readjusted. You can navigate through the SidePanel content using both mouse and keyboard.

Anatomy

<SidePanel>
	<SidePanel.Header>
		<SidePanel.Title />
	</SidePanel.Header>
	<SidePanel.Body />
	<SidePanel.Footer />
</SidePanel>;

Content

The SidePanel component follows a compositional API with subcomponents: Header, Title, Body, and Footer. Refer to the design specifications to configure each part according to your use case.

he <SidePanel.Header /> subcomponent always renders the close button by default but leaves the left side of the header open for developer customization.

The <SidePanel.Title /> must always be used as a direct child of Header. It automatically configures accessibility attributes—such as setting the appropriate aria-labelledby relationship between the title and the panel.

<SidePanel.Header>
	<SidePanel.Title>Title</SidePanel.Title>
</SidePanel.Header>

The <SidePanel.Body /> and <SidePanel.Footer /> components are flexible containers that can render any content. However, you should follow design system guidelines and recommendations to ensure consistent layout and behavior across the application.

Open panel

The SidePanel component requires the open state to be controlled, even though it defaults to an uncontrolled behavior.

Opening the SidePanel can be triggered from any button or link in the DOM, so it’s your responsibility to ensure the trigger element meets accessibility standards. This includes adding appropriate attributes such as aria-controls and aria-pressed to the button:

import {SidePanel} from '@clayui/core';
import Button from '@clayui/button';

export default function App() {
	const [open, setOpen] = useState(false);

	const ref = useRef();

	return (
		<>
			<Button
				aria-controls="sidepanel-example"
				aria-pressed={open}
				onClick={() => setOpen(!open)}
			>
				Open
			</Button>

			<div ref={ref}>
				<SidePanel
					containerRef={ref}
					id="sidepanel-example"
					onOpenChange={setOpen}
					open={open}
				/>
			</div>
		</>
	);
}

Make sure the id used in aria-controls matches the id of the <SidePanel /> component to maintain a proper relationship between the trigger and the panel.

Direction

The SidePanel can be displayed on the right or left side by setting the direction property.

<SidePanel direction="left" />

Position

The SidePanel is designed to use either absolute or fixed positioning.

absolute positioning is the default which allows the SidePanel to be used in more flexible contexts If the SidePanel cannot be placed at the edge of the window then absolute positioning should be used. When the SidePanel is positioned absolutely the header and footer may be scrolled out of view on longer pages.

fixed positioning should only be used when the SidePanel can be placed at a horizontal edge of the window without any elements above it that are not also using fixed or sticky positioning. With fixed positioning the header and footer will also be fixed and the SidePanel body will have it’s own independent scroll.

<SidePanel position="fixed" />

API Reference

SidePanel

typeof SidePanel
Parameters

{ 'aria-describedby'?: string; 'aria-label'?: string; 'aria-labelledby'?: string; as?: "aside" | "div" | "nav" | "section"; className?: string; children: React.ReactNode; containerRef: React.RefObject<HTMLElement>; defaultOpen?: boolean; direction?: "left" | "right"; displayType?: "light" | "dark"; id?: string; position?: "absolute" | "fixed"; triggerRef?: React.RefObject<HTMLElement>; }

aria-describedby

string | undefined

The global aria-describedby attribute identifies the element that describes the component.

aria-label

string | undefined

The aria-label attribute defines a string value that labels an interactive element.

aria-labelledby

string | undefined

The aria-labelledby attribute identifies the element (or elements) that labels the element it is applied to.

as

"aside" | "div" | "nav" | "section" | undefined

Custom component. aside - Secondary menus or filters, complementary information... (e.g product filters in an e-commerce site, related articles in a blog...). nav or section - If the ontent is essential for navigation, sidebar contains primary actions like important forms or sidebar is the only important content.

className

string | undefined

Sets the CSS className for the component.

children *

React.ReactNode

Children content to render a content.

containerRef *

React.RefObject<HTMLElement>

Element reference to the container of the SidePanel and primary content. NOTE: The containerRef is needed to properly handle layout and transitions of the SidePanel.

defaultOpen

boolean | undefined

Property to set the default value (uncontrolled).

direction

"left" | "right" | undefined

Direction the panel will render.

displayType

"dark" | "light" | undefined

Flag to determine which style the SidePanel will display.

id

string | undefined

The id of the component.

position

"absolute" | "fixed" | undefined

Property to determine how the SidePanel will be positioned.

triggerRef

React.RefObject<HTMLElement> | undefined

Element reference to open the SidePanel. NOTE: SidePanel automatically identifies the trigger but it may not work in some cases when the element disappears from the DOM.

UncontrolledState | ControlledState
Returns
Element
({ children, className, sticky }: Props) => JSX.Element
Parameters
Properties

children *

React.ReactNode

Children content to render a content.

className

string | undefined

Sets the CSS className for the component.

sticky

boolean | undefined

Property to make the Header sticky. Absolutely positioned SidePanel's should have the sidebar-header top CSS property adjusted to account for any fixed or sticky navigation bars on the page.

Returns
Element

Title

({ children }: React.HTMLAttributes<HTMLDivElement>) => JSX.Element
Returns
Element

Body

({ children }: Props) => JSX.Element
Parameters
Properties

children *

React.ReactNode

Children content to render a content.

Returns
Element
({ children, className, sticky }: Props) => JSX.Element
Parameters
Properties

children *

React.ReactNode

Children content to render a content.

className

string | undefined

Sets the CSS className for the component.

sticky

boolean | undefined

Property to make the Footer sticky. Absolutely positioned SidePanel's should have the sidebar-footer bottom CSS property adjusted to account for any fixed or sticky footers on the page.

Returns
Element
Edit this page on GitHub

Contributors

Evan Thibodeau, Matuzalém Teles

Last edited May 30, 2025 at 4:56:55 AM