From da8dfc011e1d54392854adb6e2c887c6a99720c9 Mon Sep 17 00:00:00 2001 From: Stefan Secrieru Date: Fri, 16 Oct 2026 15:24:07 +0300 Subject: [PATCH] feat(a11y): allow users to pass custom onclick handler to segmented controls buttons --- .../SegmentedControl.stories.tsx | 2 ++ .../SegmentedControl.test.tsx | 36 +++++++++++++++++++ .../SegmentedControl/SegmentedControl.tsx | 10 +++++- 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/components/SegmentedControl/SegmentedControl.stories.tsx b/src/components/SegmentedControl/SegmentedControl.stories.tsx index f0720f2cb..1b63a82b4 100644 --- a/src/components/SegmentedControl/SegmentedControl.stories.tsx +++ b/src/components/SegmentedControl/SegmentedControl.stories.tsx @@ -26,6 +26,7 @@ export const Default: Story = { sharable, reusable, tiny applications called Charmed Operators.

), + onClick: () => console.log("OLM clicked"), }, { label: "SDK", @@ -35,6 +36,7 @@ export const Default: Story = { them as Charms.

), + onClick: () => console.log("SDK clicked"), }, { label: "Charmhub", diff --git a/src/components/SegmentedControl/SegmentedControl.test.tsx b/src/components/SegmentedControl/SegmentedControl.test.tsx index ecdf40d99..0de7762be 100644 --- a/src/components/SegmentedControl/SegmentedControl.test.tsx +++ b/src/components/SegmentedControl/SegmentedControl.test.tsx @@ -62,6 +62,42 @@ describe("SegmentedControl", () => { ); }); + it("calls a segment onClick handler when clicked", async () => { + const user = userEvent.setup(); + let currentTarget: HTMLButtonElement | null = null; + const onClick = jest.fn((event: React.MouseEvent) => { + currentTarget = event.currentTarget; + }); + + render( + content1

, + }, + { + label: "label2", + content:

content2

, + onClick, + }, + ]} + />, + ); + + await user.click(screen.getByRole("tab", { name: "label2" })); + + expect(onClick).toHaveBeenCalledTimes(1); + expect(currentTarget).toBe(screen.getByRole("tab", { name: "label2" })); + expect(screen.getByRole("tab", { name: "label2" })).toHaveAttribute( + "aria-selected", + "true", + ); + expect(screen.getByRole("tabpanel", { name: "label2" })).toHaveTextContent( + "content2", + ); + }); + it("uses a roving tab index", () => { render( | string; + /** + * Callback function to be called when the segment is clicked. + */ + onClick?: React.MouseEventHandler; }; export type Props = { @@ -112,6 +116,7 @@ const SegmentedControl = ({ > {segments.map((segment, i) => { const tabId = `${id}-tab-${i}`; + const onClick = segment.onClick; return (