Skip to content

feat(ui): add appearance="buttons" to TabBar - #2020

Draft
MartinS-git wants to merge 4 commits into
mainfrom
feat/ui/secondary-tabs
Draft

MartinS-git wants to merge 4 commits into
mainfrom
feat/ui/secondary-tabs

Conversation

@MartinS-git

@MartinS-git MartinS-git commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Implements appearance="buttons" for TabBar and TabBarItem — a pill-style segmented control intended as a pre-defined filter UI for DataGrid and similar contexts.

Relates to #2028. Builds on #2019 (component rename/cleanup).

Changes:

  • TabBarAppearance type extended: "main" | "content" | "buttons"
  • TabBar: new tabBarButtonsStyles container (rounded pill, custom background via jn:bg-theme-tab-buttons)
  • TabBarItem: new tabBarItemButtonStyles, tabBarItemButtonActiveStyles, tabBarItemButtonInactiveStyles with jn:cursor-pointer; conditional application via isButtons
  • theme.css / global.css: 6 new semantic tokens + LT/DT color values for tab-buttons and tab-button-*
  • TabBar.stories.tsx: ButtonsAppearance story added
  • Tests added for appearance="buttons" in TabBar.test.tsx and TabBarItem.test.tsx
  • SecondaryTabs component family removed (replaced by this approach)

Test plan

  • pnpm --filter @cloudoperators/juno-ui-components build — no TS errors
  • 1475 unit tests passing
  • Storybook: ButtonsAppearance story renders pill-style tabs in both light and dark theme
  • Default and ContentAppearance stories unaffected (no regression)

Add SecondaryTabs, SecondaryTab, and SecondaryTabPanel as a segmented-control
tab strip for hierarchical navigation below primary TabNavigation.

- Controlled and uncontrolled mode (activeTab / defaultTab / onTabChange)
- Per-tab and global disabled state
- Optional icons left and right of label
- Full keyboard navigation per ARIA APG Tabs pattern:
  ArrowRight/Left with wrap-around, Home, End, skips disabled tabs
- useId() for unique per-instance IDs — no collisions on pages with
  multiple SecondaryTabs instances
- aria-controls / aria-labelledby relationship between tabs and panels
- State marker classes: juno-secondary-tab-active, juno-secondary-tab-disabled
- forwardRef + displayName on all three components
- 14 CSS design tokens added to theme.css and global.css (LT + DT)
- 36 tests covering rendering, controlled/uncontrolled, disabled, keyboard nav
- Storybook stories under WIP/SecondaryTabs

Signed-off-by: MartinS-git <info@eyepic.de>
Move SecondaryTab and SecondaryTabPanel from separate folders into
SecondaryTabs/, matching the established single-folder convention.

Rename SecondaryTab `icon` prop to `iconLeft` for consistency with
`iconRight`. Add KnownIconsEnum-based select controls for iconLeft and
iconRight in Storybook.

Update all imports and re-exports in src/index.ts accordingly.

Signed-off-by: MartinS-git <info@eyepic.de>
- Replace native disabled with aria-disabled on SecondaryTab so disabled
  tabs remain in the AT tree (NVDA/JAWS remove natively-disabled buttons)
- Add handleClick guard that returns early when aria-disabled is true
- Update keyboard-nav selector from [disabled] to [aria-disabled="true"]
- Apply roving tabindex: active non-disabled tab gets tabIndex=0, all others -1
- Add aria-orientation="horizontal" on the tablist per ARIA APG
- Wrap SecondaryTabs in forwardRef (SecondaryTab already had it)
- Apply jn:text-theme-secondary-tab-disabled token on disabled tabs
- Fix hover styles: only apply when not active AND not disabled
- Add juno-secondary-tab-active class for active-state targeting in tests/CSS
- Export useSecondaryTabsContext and SecondaryTabsContextType from package root
- Update SecondaryTab.test: replace toBeDisabled() with aria-disabled and tabIndex checks
- Update SecondaryTabs.test: replace toBeDisabled() with toHaveAttribute aria-disabled
- Add props-forwarding test to SecondaryTabPanel.test
- Remove dead Active story from SecondaryTab.stories, add Inactive story
- Add docs descriptions to all stories across all three story files
- Group all SecondaryTabs stories under WIP/SecondaryTabs/* sidebar folder
- Update changeset with full A11y rationale

Signed-off-by: MartinS-git <info@eyepic.de>
@changeset-bot

changeset-bot Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8ad6d86

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@cloudoperators/juno-ui-components Minor
@cloudoperators/juno-app-carbon Patch
@cloudoperators/juno-app-doop Patch
@cloudoperators/juno-app-example Patch
@cloudoperators/juno-app-greenhouse Patch
@cloudoperators/juno-app-heureka Patch
@cloudoperators/juno-app-supernova Patch
@cloudoperators/juno-app-template Patch
@cloudoperators/juno-messages-provider Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Signed-off-by: MartinS-git <info@eyepic.de>
@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

🚀 View preview at
https://cloudoperators.github.io/juno/pr-preview/pr-2020/

Built to branch gh-pages at 2026-09-29 09:12 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Disabled-state handling, form submission behavior, initial keyboard focus, and tab-panel accessibility require correction.

Review effort: Balanced
Findings: 5 Medium severity · 3 Low severity

Open (8)
What changed in this PR

Adds an accessible SecondaryTabs component family to the UI design system.

Changes:

  • Adds controlled/uncontrolled tabs, panels, keyboard navigation, and disabled states.
  • Adds theme tokens and package exports.
  • Adds Vitest coverage, Storybook stories, and release notes.
File Description
theme.css Adds secondary-tab theme tokens.
global.css Adds global theme token mappings.
src/​index.ts Exports the new public API.
SecondaryTabs.component.tsx Implements tab context and container.
SecondaryTab.component.tsx Implements tabs and keyboard navigation.
SecondaryTabPanel.component.tsx Implements associated content panels.
SecondaryTabs.test.tsx Tests container behavior.
SecondaryTab.test.tsx Tests individual tabs.
SecondaryTabPanel.test.tsx Tests panels and ref forwarding.
SecondaryTabs.stories.tsx Demonstrates complete tab sets.
SecondaryTab.stories.tsx Demonstrates tab states and icons.
SecondaryTabPanel.stories.tsx Demonstrates panel usage.
SecondaryTabs/​index.ts Adds component-level exports.
.changeset/​secondary-tabs-component.md Documents the minor release.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread .changeset/secondary-tabs-component.md
@MartinS-git MartinS-git changed the title feat(ui): add SecondaryTabs component family feat(ui): add appearance="buttons" to TabBar Oct 9, 2026
@MartinS-git
MartinS-git requested a balanced review from Copilot October 9, 2026 13:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread .changeset/secondary-tabs-component.md

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants