From 021a35993992d82d927ca7292743286ff68182c5 Mon Sep 17 00:00:00 2001 From: Mohamed Fall Date: Sun, 4 Jan 2026 13:18:24 +0000 Subject: [PATCH 1/3] feat(Tabs): add tabListAriaLabel prop Signed-off-by: Mohamed Fall --- packages/react-core/src/components/Tabs/Tabs.tsx | 11 ++++++++++- .../Tabs/__tests__/__snapshots__/Tabs.test.tsx.snap | 13 +++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/react-core/src/components/Tabs/Tabs.tsx b/packages/react-core/src/components/Tabs/Tabs.tsx index 1c997f8c095..fd29ee962e8 100644 --- a/packages/react-core/src/components/Tabs/Tabs.tsx +++ b/packages/react-core/src/components/Tabs/Tabs.tsx @@ -61,6 +61,8 @@ export interface TabsProps onAdd?: (event: React.MouseEvent) => void; /** Aria-label for the add button */ addButtonAriaLabel?: string; + /** Aria-label for the list element */ + tabListAriaLabel?: string; /** Uniquely identifies the tabs */ id?: string; /** Flag indicating that the add button is disabled when onAdd is passed in */ @@ -500,6 +502,7 @@ class Tabs extends Component { toggleText, toggleAriaLabel, addButtonAriaLabel, + tabListAriaLabel, onToggle, onClose, onAdd, @@ -626,7 +629,13 @@ class Tabs extends Component { /> )} -
    +
      {isOverflowHorizontal ? filteredChildrenWithoutOverflow : filteredChildren} {hasOverflowTab && }
    diff --git a/packages/react-core/src/components/Tabs/__tests__/__snapshots__/Tabs.test.tsx.snap b/packages/react-core/src/components/Tabs/__tests__/__snapshots__/Tabs.test.tsx.snap index 7a0666e5962..88db1bde663 100644 --- a/packages/react-core/src/components/Tabs/__tests__/__snapshots__/Tabs.test.tsx.snap +++ b/packages/react-core/src/components/Tabs/__tests__/__snapshots__/Tabs.test.tsx.snap @@ -12,6 +12,7 @@ exports[`should render accessible tabs 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
      @@ -129,6 +130,7 @@ exports[`should render box tabs 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
        @@ -288,6 +290,7 @@ exports[`should render box tabs of secondary variant 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
          @@ -453,6 +456,7 @@ exports[`should render expandable vertical tabs 1`] = `
            @@ -612,6 +616,7 @@ exports[`should render filled tabs 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
              @@ -729,6 +734,7 @@ exports[`should render simple tabs 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
                @@ -888,6 +894,7 @@ exports[`should render subtabs 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
                  @@ -974,6 +981,7 @@ exports[`should render subtabs 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0; --pf-v6-c-tabs--link-accent--start: 0;" >
                    @@ -1117,6 +1125,7 @@ exports[`should render tabs with eventKey Strings 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0; --pf-v6-c-tabs--link-accent--start: 0;" >
                      @@ -1235,6 +1244,7 @@ exports[`should render tabs with no bottom border 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
                        @@ -1352,6 +1362,7 @@ exports[`should render tabs with separate content 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
                          @@ -1478,6 +1489,7 @@ exports[`should render uncontrolled tabs 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
                            @@ -1637,6 +1649,7 @@ exports[`should render vertical tabs 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
                              From 7c7ed846fa309e5fa54eef21ee71d4961158c59b Mon Sep 17 00:00:00 2001 From: fallmo <58644999+fallmo@users.noreply.github.com> Date: Fri, 9 Jan 2026 15:34:37 +0000 Subject: [PATCH 2/3] Update packages/react-core/src/components/Tabs/Tabs.tsx Co-authored-by: Eric Olkowski <70952936+thatblindgeye@users.noreply.github.com> --- packages/react-core/src/components/Tabs/Tabs.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-core/src/components/Tabs/Tabs.tsx b/packages/react-core/src/components/Tabs/Tabs.tsx index fd29ee962e8..866d377464a 100644 --- a/packages/react-core/src/components/Tabs/Tabs.tsx +++ b/packages/react-core/src/components/Tabs/Tabs.tsx @@ -61,7 +61,7 @@ export interface TabsProps onAdd?: (event: React.MouseEvent) => void; /** Aria-label for the add button */ addButtonAriaLabel?: string; - /** Aria-label for the list element */ + /** A readable string to create an accessible name for the tablist element. This can be used to differentiate multiple tablists on a page, and should be used for subtabs. */ tabListAriaLabel?: string; /** Uniquely identifies the tabs */ id?: string; From e323917381315fb1417a14a4c9f792e099af60a1 Mon Sep 17 00:00:00 2001 From: Mohamed Fall Date: Fri, 9 Jan 2026 23:48:05 +0000 Subject: [PATCH 3/3] feat(Tabs): add tabListAriaLabelledBy prop, update accessibility tests, and examples Signed-off-by: Mohamed Fall --- .../react-core/src/components/Tabs/Tabs.tsx | 6 +- .../components/Tabs/__tests__/Tabs.test.tsx | 48 +++ .../__snapshots__/Tabs.test.tsx.snap | 273 +++++++++++++++++- .../src/components/Tabs/examples/Tabs.md | 2 + .../Tabs/examples/TabsNavSubtab.tsx | 2 + .../components/Tabs/examples/TabsSubtabs.tsx | 2 + 6 files changed, 319 insertions(+), 14 deletions(-) diff --git a/packages/react-core/src/components/Tabs/Tabs.tsx b/packages/react-core/src/components/Tabs/Tabs.tsx index 866d377464a..d06f4fb920a 100644 --- a/packages/react-core/src/components/Tabs/Tabs.tsx +++ b/packages/react-core/src/components/Tabs/Tabs.tsx @@ -63,6 +63,8 @@ export interface TabsProps addButtonAriaLabel?: string; /** A readable string to create an accessible name for the tablist element. This can be used to differentiate multiple tablists on a page, and should be used for subtabs. */ tabListAriaLabel?: string; + /** Id of an element that provides an accessible name for the tablist. Use this when a visible label already exists on the page. */ + tabListAriaLabelledBy?: string; /** Uniquely identifies the tabs */ id?: string; /** Flag indicating that the add button is disabled when onAdd is passed in */ @@ -503,6 +505,7 @@ class Tabs extends Component { toggleAriaLabel, addButtonAriaLabel, tabListAriaLabel, + tabListAriaLabelledBy, onToggle, onClose, onAdd, @@ -630,7 +633,8 @@ class Tabs extends Component { )}
                                { + const { asFragment } = render( + + "Tab item 1"}> + Tab 1 section + + "Tab item 2"}> + Tab 2 section + + + ); + + expect(asFragment()).toMatchSnapshot(); +}); + +test('should render tablist aria-labelledby when provided', () => { + const { asFragment } = render( + <> +

                                My tabs heading

                                + + "Tab item 1"}> + Tab 1 section + + "Tab item 2"}> + Tab 2 section + + + + ); + + expect(asFragment()).toMatchSnapshot(); +}); + +test('should not render tablist aria-label or aria-labelledby when neither is provided', () => { + const { asFragment } = render( + + "Tab item 1"}> + Tab 1 section + + "Tab item 2"}> + Tab 2 section + + + ); + + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/Tabs/__tests__/__snapshots__/Tabs.test.tsx.snap b/packages/react-core/src/components/Tabs/__tests__/__snapshots__/Tabs.test.tsx.snap index 88db1bde663..6586f557648 100644 --- a/packages/react-core/src/components/Tabs/__tests__/__snapshots__/Tabs.test.tsx.snap +++ b/packages/react-core/src/components/Tabs/__tests__/__snapshots__/Tabs.test.tsx.snap @@ -12,7 +12,6 @@ exports[`should render accessible tabs 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
                                  @@ -130,7 +129,6 @@ exports[`should render box tabs 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
                                    @@ -290,7 +288,6 @@ exports[`should render box tabs of secondary variant 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
                                      @@ -456,7 +453,6 @@ exports[`should render expandable vertical tabs 1`] = `
                                        @@ -616,7 +612,6 @@ exports[`should render filled tabs 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
                                          @@ -734,7 +729,6 @@ exports[`should render simple tabs 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
                                            @@ -894,7 +888,6 @@ exports[`should render subtabs 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
                                              @@ -981,7 +974,6 @@ exports[`should render subtabs 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0; --pf-v6-c-tabs--link-accent--start: 0;" >
                                                @@ -1114,6 +1106,266 @@ exports[`should render subtabs 1`] = ` `; +exports[`should render tablist aria-label when provided 1`] = ` + +
                                                +
                                                  + + +
                                                +
                                                +
                                                + Tab 1 section +
                                                + +
                                                +`; + +exports[`should render tablist aria-labelledby when provided 1`] = ` + +

                                                + My tabs heading +

                                                +
                                                +
                                                  + + +
                                                +
                                                +
                                                + Tab 1 section +
                                                + +
                                                +`; + + +exports[`should not render tablist aria-label or aria-labelledby when neither is provided 1`] = ` + +
                                                +
                                                  + + +
                                                +
                                                +
                                                + Tab 1 section +
                                                + +
                                                +`; + exports[`should render tabs with eventKey Strings 1`] = `
                                                  @@ -1244,7 +1495,6 @@ exports[`should render tabs with no bottom border 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
                                                    @@ -1362,7 +1612,6 @@ exports[`should render tabs with separate content 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
                                                      @@ -1489,7 +1738,6 @@ exports[`should render uncontrolled tabs 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
                                                        @@ -1649,7 +1897,6 @@ exports[`should render vertical tabs 1`] = ` style="--pf-v6-c-tabs--link-accent--length: 0px; --pf-v6-c-tabs--link-accent--start: 0px;" >
                                                          diff --git a/packages/react-core/src/components/Tabs/examples/Tabs.md b/packages/react-core/src/components/Tabs/examples/Tabs.md index 094482a76b4..5e2a897f0da 100644 --- a/packages/react-core/src/components/Tabs/examples/Tabs.md +++ b/packages/react-core/src/components/Tabs/examples/Tabs.md @@ -159,6 +159,8 @@ Use subtabs within other components, like modals. Subtabs have less visually pro To apply subtab styling to tabs, use the `isSubtab` property. +For accessibility, give the primary tablist an accessible name (for example, `tabListAriaLabel="Primary"`) and give any subtab tablist an accessible name that matches the currently selected primary tab (for example, `tabListAriaLabel="Users"`). + ```ts file="./TabsSubtabs.tsx" ``` diff --git a/packages/react-core/src/components/Tabs/examples/TabsNavSubtab.tsx b/packages/react-core/src/components/Tabs/examples/TabsNavSubtab.tsx index 4b1223df012..bb64a711245 100644 --- a/packages/react-core/src/components/Tabs/examples/TabsNavSubtab.tsx +++ b/packages/react-core/src/components/Tabs/examples/TabsNavSubtab.tsx @@ -27,6 +27,7 @@ export const TabsNavSubtab: React.FunctionComponent = () => { onSelect={handleTabClickFirst} component={TabsComponent.nav} aria-label="Tabs in the sub tabs with nav element example" + tabListAriaLabel="Primary" > Users} href="#" aria-label="Subtabs with nav content users"> { onSelect={handleTabClickSecond} aria-label="Local secondary" component={TabsComponent.nav} + tabListAriaLabel="Users" > Item 1} href="#"> Item 1 item section diff --git a/packages/react-core/src/components/Tabs/examples/TabsSubtabs.tsx b/packages/react-core/src/components/Tabs/examples/TabsSubtabs.tsx index 0c0428d62e2..73fe095dd69 100644 --- a/packages/react-core/src/components/Tabs/examples/TabsSubtabs.tsx +++ b/packages/react-core/src/components/Tabs/examples/TabsSubtabs.tsx @@ -33,6 +33,7 @@ export const TabsSubtabs: React.FunctionComponent = () => { onSelect={handleTabClickFirst} isBox={isBox} aria-label="Tabs in the tabs with subtabs example" + tabListAriaLabel="Primary" role="region" > Users} aria-label="Tabs with subtabs content users"> @@ -41,6 +42,7 @@ export const TabsSubtabs: React.FunctionComponent = () => { role="region" activeKey={activeTabKey2} isSubtab + tabListAriaLabel="Users" onSelect={handleTabClickSecond} > Subtab item 1}>