Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ export interface AdaptiveSidebarProps
open: boolean;
/** Whether to render the sidebar as a modal component instead of as an inline sidebar */
renderAsModal?: boolean;
/** Prop to specify the aria-label of the component, applied when the component is rendered as a modal */
"aria-label"?: string;
/** Prop to specify the aria-labelledby property of the component, applied when the component is rendered as a modal */
"aria-labelledby"?: string;
/** The width of the sidebar */
width?: string;
}
Expand All @@ -53,6 +57,8 @@ export const AdaptiveSidebar = ({
renderAsModal = false,
width = "320px",
restoreFocusOnClose = false,
"aria-label": ariaLabel,
"aria-labelledby": ariaLabelledBy,
...props
}: AdaptiveSidebarProps) => {
const largeScreen = useIsAboveBreakpoint(adaptiveBreakpoint);
Expand Down Expand Up @@ -116,6 +122,8 @@ export const AdaptiveSidebar = ({
open={open}
p={0}
ref={adaptiveSidebarRef}
aria-label={ariaLabel}
aria-labelledby={ariaLabelledBy}
>
<Box
data-role="adaptive-sidebar-content-wrapper"
Expand Down
3 changes: 3 additions & 0 deletions src/components/adaptive-sidebar/adaptive-sidebar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ closed by the user, and can be used to display additional information or actions
To use the adaptive sidebar, import `AdaptiveSidebar` into your project. All content within the `AdaptiveSidebar` component is determined by the user; by
default, the component will be empty, allowing for complete control of layout, etc.

As the `AdaptiveSidebar` can be rendered as a modal, it is **strongly** recommended that the component is given an accessible name.
This can be generated via the `aria-label` or `aria-labelledby` attributes.

```javascript
import AdaptiveSidebar from "carbon-react/lib/components/adaptive-sidebar";
```
Expand Down
28 changes: 28 additions & 0 deletions src/components/adaptive-sidebar/adaptive-sidebar.pw.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,5 +132,33 @@ test.describe("Component properties", () => {
await checkAccessibility(page);
});
});

test("should pass accessibility tests for Adaptive Sidebar when `renderAsModal` is true and an accessible name is provided via `aria-label`", async ({
mount,
page,
}) => {
await mount(
<DefaultAdaptiveSidebar renderAsModal aria-label="sidebar" open />,
);

// We're skipping colour contrast rules here as axe is incorrectly registering the disabled UI with black text as a violation
await checkAccessibility(page, undefined, "color-contrast");
});

test("should pass accessibility tests for Adaptive Sidebar when `renderAsModal` is true and an accessible name is provided via `aria-labelledby`", async ({
mount,
page,
}) => {
await mount(
<DefaultAdaptiveSidebar
renderAsModal
aria-labelledby="accessible-name"
open
/>,
);

// We're skipping colour contrast rules here as axe is incorrectly registering the disabled UI with black text as a violation
await checkAccessibility(page, undefined, "color-contrast");
});
});
});
41 changes: 35 additions & 6 deletions src/components/adaptive-sidebar/adaptive-sidebar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,11 @@ export const Basic: Story = () => {
eu elit eget lacus fermentum porta at ut dui.
</Typography>
</Box>
<AdaptiveSidebar open={adaptiveSidebarOpen} width="300px">
<AdaptiveSidebar
aria-label="adaptive-sidebar"
open={adaptiveSidebarOpen}
width="300px"
>
<Box p={2} display="flex" flexDirection="column">
<Button onClick={() => setAdaptiveSidebarOpen(false)} mb={2}>
Close
Expand Down Expand Up @@ -129,7 +133,11 @@ export const Default: Story = () => {
eu elit eget lacus fermentum porta at ut dui.
</Typography>
</Box>
<AdaptiveSidebar open={adaptiveSidebarOpen} width="300px">
<AdaptiveSidebar
aria-label="adaptive-sidebar"
open={adaptiveSidebarOpen}
width="300px"
>
<Box
display="flex"
flexDirection="row"
Expand Down Expand Up @@ -182,7 +190,11 @@ export const Complex: Story = () => {
dui.
</Typography>
</Box>
<AdaptiveSidebar open={adaptiveSidebarOpen} width="500px">
<AdaptiveSidebar
aria-label="adaptive-sidebar"
open={adaptiveSidebarOpen}
width="500px"
>
<Box display="flex" flexDirection="column" pb={5}>
<Button onClick={() => setAdaptiveSidebarOpen(false)} m={2}>
Close
Expand Down Expand Up @@ -247,7 +259,11 @@ export const WithCustomWidth: Story = () => {
<Box display="flex" flexDirection="row">
{CommonTemplate(adaptiveSidebarOpen, setAdaptiveSidebarOpen)}

<AdaptiveSidebar open={adaptiveSidebarOpen} width="70%">
<AdaptiveSidebar
aria-label="adaptive-sidebar"
open={adaptiveSidebarOpen}
width="70%"
>
<Box display="flex" flexDirection="column">
<Box
display="flex"
Expand Down Expand Up @@ -284,7 +300,11 @@ export const WithCustomHeight: Story = () => {
>
{CommonTemplate(adaptiveSidebarOpen, setAdaptiveSidebarOpen)}

<AdaptiveSidebar open={adaptiveSidebarOpen} height="98vh">
<AdaptiveSidebar
aria-label="adaptive-sidebar"
open={adaptiveSidebarOpen}
height="98vh"
>
<Box display="flex" flexDirection="column">
<Box
display="flex"
Expand Down Expand Up @@ -376,6 +396,7 @@ export const BackgroundVariants: Story = () => {
</Box>

<AdaptiveSidebar
aria-label="adaptive-sidebar"
backgroundColor={colour as "white" | "black" | "app"}
open={adaptiveSidebarOpen}
width="300px"
Expand Down Expand Up @@ -419,6 +440,7 @@ export const WithAdaptiveBreakpoint: Story = () => {
{CommonTemplate(adaptiveSidebarOpen, setAdaptiveSidebarOpen)}

<AdaptiveSidebar
aria-label="adaptive-sidebar"
adaptiveBreakpoint={650}
open={adaptiveSidebarOpen}
width="300px"
Expand Down Expand Up @@ -454,7 +476,12 @@ export const RenderAsModal: Story = () => {
<Box display="flex" flexDirection="row">
{CommonTemplate(adaptiveSidebarOpen, setAdaptiveSidebarOpen)}

<AdaptiveSidebar renderAsModal open={adaptiveSidebarOpen} width="300px">
<AdaptiveSidebar
aria-label="adaptive-sidebar"
renderAsModal
open={adaptiveSidebarOpen}
width="300px"
>
<Box display="flex" flexDirection="column" m={2}>
<Box
display="flex"
Expand Down Expand Up @@ -508,6 +535,7 @@ export const WithCustomBorderColor: Story = () => {
</Typography>
</Box>
<AdaptiveSidebar
aria-label="adaptive-sidebar"
open={adaptiveSidebarOpen}
width="300px"
borderColor="--colorsActionMajor500"
Expand Down Expand Up @@ -590,6 +618,7 @@ export const Hidden: Story = () => {
</Typography>
</Box>
<AdaptiveSidebar
aria-label="adaptive-sidebar"
hidden={adaptiveSidebarHidden}
open={adaptiveSidebarOpen}
width="300px"
Expand Down
28 changes: 27 additions & 1 deletion src/components/adaptive-sidebar/adaptive-sidebar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const MockApp = ({
</Typography>
</Box>
<AdaptiveSidebar open={adaptiveSidebarOpen} {...props}>
My Content
<span id="accessible-name">My Content</span>
<Button data-role="custom-close-button" onClick={() => {}}>
Custom close
</Button>
Expand Down Expand Up @@ -206,6 +206,32 @@ test("should render the AdaptiveSidebar component as a modal", async () => {
expect(screen.getByTestId("modal-background")).toBeInTheDocument();
});

test("when rendered as a modal, the accessible name of the modal is set via `aria-label`", async () => {
const user = userEvent.setup();

render(<MockApp renderAsModal aria-label="sidebar" />);

const openButton = screen.getByTestId("adaptive-sidebar-control-button");
await user.click(openButton);

const modal = screen.getByRole("dialog");

expect(modal).toHaveAccessibleName("sidebar");
});

test("when rendered as a modal, the accessible name of the modal is set via `aria-labelledby`", async () => {
const user = userEvent.setup();

render(<MockApp renderAsModal aria-labelledby="accessible-name" />);

const openButton = screen.getByTestId("adaptive-sidebar-control-button");
await user.click(openButton);

const modal = screen.getByRole("dialog");

expect(modal).toHaveAccessibleName("My Content");
});

test("should close the AdaptiveSidebar component when the control button is clicked", async () => {
const user = userEvent.setup();

Expand Down
2 changes: 1 addition & 1 deletion src/components/adaptive-sidebar/components.test-pw.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const DefaultAdaptiveSidebar = ({ ...props }) => {
>
Close
</Button>
Adaptive sidebar content
<span id="accessible-name">Adaptive sidebar content</span>
</AdaptiveSidebar>
</Box>
</>
Expand Down
Loading