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 (