Skip to content

feat(tabs): new tedi-ready component #14 - #481

Merged
mart-sessman merged 13 commits into
rcfrom
feat/14-tabs-new-tedi-ready
Jun 30, 2026
Merged

feat(tabs): new tedi-ready component #14#481
mart-sessman merged 13 commits into
rcfrom
feat/14-tabs-new-tedi-ready

Conversation

@mart-sessman

@mart-sessman mart-sessman commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Migration Guide — Tabs

This release introduces a TEDI-Ready Tabs component (@tedi-design-system/angular). It replaces the community Tabs (@tedi-design-system/angular/community). The two share the same root selector (tedi-tabs) but have a completely different structure and selection model, so existing community usage must be migrated.

Community Tabs → TEDI-Ready Tabs

What changed: The community Tabs exposed tedi-tabs + [tedi-tab] + tedi-tab-content, with selection driven per-tab via a [selected] model and tabSelected output, optional router integration via RouterLinkActive, and an automatic mobile "More" dropdown. The TEDI-Ready Tabs is a full WAI-ARIA tab pattern: a required tedi-tabs-list wrapper holds button[tedi-tabs-trigger] items, selection is centralized on the root via value/defaultValue/valueChange, panels are tedi-tabs-content, and overflow is configurable via overflowMode ("dropdown" | "scroll").

Why: To deliver the official TEDI design-system Tabs with a single source of truth for the active tab, full keyboard support (Arrow/Home/End, roving tabindex), correct tablist/tab/tabpanel semantics, icon support, and explicit overflow handling.

Before (community):

import { TabsComponent, TabComponent, TabContentComponent }
  from '@tedi-design-system/angular/community';
<tedi-tabs>
  <button tedi-tab tabId="tab-1" [selected]="true">Health timeline</button>
  <button tedi-tab tabId="tab-2">Course of diseases</button>
  <button tedi-tab tabId="tab-3" disabled>Medication history</button>

  <tedi-tab-content tabId="tab-1">Timeline content</tedi-tab-content>
  <tedi-tab-content tabId="tab-2">Diseases content</tedi-tab-content>
  <tedi-tab-content tabId="tab-3">Medication content</tedi-tab-content>
</tedi-tabs>

After (TEDI-Ready):

import {
  TabsComponent, TabsListComponent, TabsTriggerComponent, TabsContentComponent
} from '@tedi-design-system/angular';
<tedi-tabs defaultValue="tab-1">
  <tedi-tabs-list aria-label="Health tabs">
    <button tedi-tabs-trigger id="tab-1">Health timeline</button>
    <button tedi-tabs-trigger id="tab-2">Course of diseases</button>
    <button tedi-tabs-trigger id="tab-3" [disabled]="true">Medication history</button>
  </tedi-tabs-list>

  <tedi-tabs-content id="tab-1">Timeline content</tedi-tabs-content>
  <tedi-tabs-content id="tab-2">Diseases content</tedi-tabs-content>
  <tedi-tabs-content id="tab-3">Medication content</tedi-tabs-content>
</tedi-tabs>

Controlled selection

Replace per-tab [selected]/(tabSelected) with a single binding on the root:

<!-- Before: each tab managed its own [selected] / (tabSelected) -->
<button tedi-tab tabId="tab-1" [(selected)]="..."> ... </button>

<!-- After: one binding on the root -->
<tedi-tabs [(value)]="activeTab"> ... </tedi-tabs>
<!-- or [value]="activeTab" (valueChange)="activeTab = $event" -->

Icons

The TEDI-Ready trigger has a first-class icon input (community had none; you projected your own):

<button tedi-tabs-trigger id="tab-1" icon="table_chart">Table</button>

Overflow

The community auto mobile "More" dropdown is replaced by an explicit overflowMode on the list:

<!-- collapses overflowing tabs into a "More" menu (default) -->
<tedi-tabs-list aria-label="" overflowMode="dropdown"></tedi-tabs-list>

<!-- horizontal scroll with fade edges -->
<tedi-tabs-list aria-label="" overflowMode="scroll"></tedi-tabs-list>

Router-driven tabs

The community [tedi-tab] integrated RouterLinkActive to derive the active tab from the URL. The TEDI-Ready Tabs does not build router activation into the trigger; instead, drive value from your routing state and use an id-less tedi-tabs-content as an always-rendered panel for a router outlet:

<tedi-tabs [value]="activeRouteId">
  <tedi-tabs-list aria-label="Sections">
    <button tedi-tabs-trigger id="overview" routerLink="overview">Overview</button>
    <button tedi-tabs-trigger id="details" routerLink="details">Details</button>
  </tedi-tabs-list>
  <tedi-tabs-content><router-outlet /></tedi-tabs-content>
</tedi-tabs>

Key changes

  • Import path: @tedi-design-system/angular/community@tedi-design-system/angular.
  • New required wrapper: triggers must be nested inside tedi-tabs-list (community had no list wrapper). Add aria-label (or aria-labelledby) on the list for accessibility.
  • Tab selector: [tedi-tab] (any element) → button[tedi-tabs-trigger] (must be a native <button>).
  • Tab id input: tabIdid (on the trigger).
  • Selection model: per-tab selected (model) + tabSelected (output) → centralized value / defaultValue (inputs) + valueChange (output) on tedi-tabs.
  • Panel selector & input: tedi-tab-content with tabIdtedi-tabs-content with id. An id-less panel always renders (router-outlet use case).
  • Panel rendering: the active panel is now lazily rendered (mounted only while active) instead of always present.
  • Icons: new icon input on the trigger.
  • Overflow: automatic mobile "More" dropdown → explicit overflowMode="dropdown" | "scroll" on the list.
  • Router integration removed from the tab: RouterLinkActive host-directive behavior is no longer built in; drive value from routing instead.
  • disabled: unchanged in name; now applied to the native <button> trigger.

Summary — old → new mapping

Community (old) TEDI-Ready (new)
import … from '@tedi-design-system/angular/community' import … from '@tedi-design-system/angular'
<tedi-tabs> (selection lived on tabs) <tedi-tabs [(value)]> / defaultValue / (valueChange)
(no list wrapper) <tedi-tabs-list aria-label="…" [overflowMode]> (required wrapper)
<button tedi-tab tabId="x"> <button tedi-tabs-trigger id="x">
[selected] (model), (tabSelected) central value / valueChange on root
disabled disabled (on the <button>)
(project your own icon) icon input on trigger
RouterLinkActive built into [tedi-tab] drive value from routing; <tedi-tabs-content> (no id) for outlet
<tedi-tab-content tabId="x"> <tedi-tabs-content id="x">
auto mobile "More" dropdown overflowMode="dropdown" (default) or "scroll"

Note: because both versions use the root selector tedi-tabs, do not import the community and TEDI-Ready Tabs into the same component scope — switch the import path and migrate the markup together.

Summary by CodeRabbit

  • New Features
    • Added the TEDI-Ready tabs experience (triggers, tab list, panels) with controlled/uncontrolled selection, keyboard navigation, ARIA wiring, and overflow handling (“More” dropdown and scroll mode).
    • Added clipContent to dropdown item label rendering to control ellipsis/overflow behavior.
  • Bug Fixes
    • Tab panel content is shown only for the active tab.
    • Disabled dropdown items no longer take focus on mouse press.
  • Documentation
    • Added TEDI-Ready Tabs component documentation and expanded Storybook coverage (including overflow scenarios).
  • Deprecations
    • Marked legacy community tabs components as deprecated in favor of TEDI-Ready tabs.

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@mart-sessman, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 30 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 528ba8d3-3e29-4cca-902d-19e5dde78584

📥 Commits

Reviewing files that changed from the base of the PR and between f558340 and 94a1da1.

📒 Files selected for processing (2)
  • tedi/components/navigation/tabs/tabs-list/tabs-list.component.ts
  • tedi/components/navigation/tabs/tabs-trigger/tabs-trigger.component.ts
📝 Walkthrough

Walkthrough

Adds the TEDI-ready tabs component family, deprecates the community tabs API, and updates dropdown item label clipping behavior and related Storybook/docs wiring.

Changes

TEDI-Ready Tabs implementation

Layer / File(s) Summary
TabsComponent public API and exports
tedi/components/navigation/tabs/tabs.component.ts, tedi/components/navigation/tabs/tabs.component.scss, tedi/components/navigation/tabs/index.ts, tedi/components/navigation/index.ts
TabsComponent adds controlled and uncontrolled selection state, the root display style, and the navigation barrels now re-export the tabs module.
Keyboard navigation helper
tedi/components/navigation/tabs/tabs-helpers.ts
Adds tablist key handling for Arrow, Home, and End navigation, including target lookup, focus movement, and scroll-into-view behavior.
TabsTriggerComponent button and interaction
tedi/components/navigation/tabs/_tabs.mixins.scss, tedi/components/navigation/tabs/tabs-trigger/*
Adds the shared tab button mixin and the trigger component template, ARIA wiring, selection state, icon rendering, and click/keydown handling.
TabsListComponent overflow handling
tedi/components/navigation/tabs/tabs-list/*
Adds the tab list container, dropdown overflow mode, scroll overflow mode, resize-based overflow checks, scroll fade state, and list styles.
TabsContentComponent panel rendering
tedi/components/navigation/tabs/tabs-content/*
Adds the tab panel component with active-state detection, panel ARIA attributes, conditional content rendering, and panel styling.
Tests, stories, and documentation
tedi/components/navigation/tabs/tabs.spec.ts, tedi/components/navigation/tabs/tabs.stories.ts, skills/tedi-angular/references/components.md
Adds tab behavior tests, Storybook examples for the new API and variants, and reference docs for the tabs component family.

Community tabs deprecation notices

Layer / File(s) Summary
Community component deprecations and Storybook status
community/components/navigation/tabs/tab-content/tab-content.component.ts, community/components/navigation/tabs/tab/tab.component.ts, community/components/navigation/tabs/tabs.component.ts, community/components/navigation/tabs/tabs.stories.ts
Adds deprecation JSDoc to the community tabs components and marks the community tabs Storybook entry as deprecated and existing in TEDI-ready.

Dropdown item label clipping

Layer / File(s) Summary
Dropdown clipping API and rendering
tedi/components/overlay/dropdown/dropdown-item-value/dropdown-item-value-label.component.ts, tedi/components/overlay/dropdown/dropdown-item-value/dropdown-item-value.component.scss, tedi/components/overlay/dropdown/dropdown-item/dropdown-item.component.ts, tedi/components/overlay/dropdown/dropdown-item/dropdown-item.component.html, tedi/components/overlay/dropdown/dropdown-item-value/dropdown-item-value.stories.ts, tedi/components/overlay/dropdown/dropdown.stories.ts
Adds the clipContent input, the no-clip label styling, the forwarded label binding, disabled-item mouse handling, and matching Storybook controls and examples.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • [Tabs]: design improvements react#688 — The tabs changes add overflow handling, rounded container styling, and focus-ring behavior that align with the issue’s tabs-related design update.

Possibly related PRs

  • TEDI-Design-System/angular#448 — Both PRs touch DropdownItemComponent and extend its behavior/API with additional item interaction inputs/handling.

Suggested reviewers

  • airikej
  • ly-tempel-bitweb
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the PR’s main change: introducing a new TEDI-Ready tabs component.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/14-tabs-new-tedi-ready

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@mart-sessman

Copy link
Copy Markdown
Contributor Author

@coderabbitai review it

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

@mart-sessman Sure, I'll review the PR now!

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Base automatically changed from feat/9-button-group-tedi-ready to rc June 19, 2026 12:25
@codecov

codecov Bot commented Jun 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.68508% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
tedi/components/navigation/tabs/tabs-helpers.ts 93.33% 2 Missing ⚠️
...s/navigation/tabs/tabs-list/tabs-list.component.ts 97.50% 2 Missing ⚠️
.../dropdown/dropdown-item/dropdown-item.component.ts 33.33% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tedi/components/navigation/tabs/tabs-list/tabs-list.component.ts`:
- Around line 151-157: In tabs-list.component.ts, the overflow state in the
tabs-list logic is using a latched naturalWidth value that is only set when
overflow first appears, so later content growth can incorrectly clear
isOverflowing. Update the logic in the overflow check around isOverflowing and
naturalWidth so naturalWidth is refreshed when the list width increases, and
make the overflow recalculation in the tabs-list component use the latest
scrollWidth before deciding whether to set isOverflowing back to false.

In `@tedi/components/navigation/tabs/tabs.spec.ts`:
- Around line 230-231: The specs are mutating the tab input directly instead of
using the TestBed input API. Update the affected tests in tabs.spec.ts to set
the component’s signal input through fixture.componentRef.setInput(...) for the
value input on the tabs host before calling fixture.detectChanges(), and apply
the same pattern to the other matching cases in this spec file so the tests
follow the repository convention.
- Around line 22-33: The tab spec setup mutates shared globals in beforeAll by
replacing ResizeObserver and Element.prototype.scrollIntoView, so add an
afterAll cleanup in tabs.spec.ts to restore both mocks to their original
implementations. Use the existing beforeAll block and the
resizeCallback/scrollIntoView setup as the anchor, and make sure the teardown
fully resets global.ResizeObserver and Element.prototype.scrollIntoView so other
specs are not affected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 25d77339-ac61-4662-b015-93a4b87d2c11

📥 Commits

Reviewing files that changed from the base of the PR and between b323bad and ccced9b.

📒 Files selected for processing (22)
  • community/components/navigation/tabs/tab-content/tab-content.component.ts
  • community/components/navigation/tabs/tab/tab.component.ts
  • community/components/navigation/tabs/tabs.component.ts
  • community/components/navigation/tabs/tabs.stories.ts
  • skills/tedi-angular/references/components.md
  • tedi/components/navigation/index.ts
  • tedi/components/navigation/tabs/_tabs.mixins.scss
  • tedi/components/navigation/tabs/index.ts
  • tedi/components/navigation/tabs/tabs-content/tabs-content.component.html
  • tedi/components/navigation/tabs/tabs-content/tabs-content.component.scss
  • tedi/components/navigation/tabs/tabs-content/tabs-content.component.ts
  • tedi/components/navigation/tabs/tabs-helpers.ts
  • tedi/components/navigation/tabs/tabs-list/tabs-list.component.html
  • tedi/components/navigation/tabs/tabs-list/tabs-list.component.scss
  • tedi/components/navigation/tabs/tabs-list/tabs-list.component.ts
  • tedi/components/navigation/tabs/tabs-trigger/tabs-trigger.component.html
  • tedi/components/navigation/tabs/tabs-trigger/tabs-trigger.component.scss
  • tedi/components/navigation/tabs/tabs-trigger/tabs-trigger.component.ts
  • tedi/components/navigation/tabs/tabs.component.scss
  • tedi/components/navigation/tabs/tabs.component.ts
  • tedi/components/navigation/tabs/tabs.spec.ts
  • tedi/components/navigation/tabs/tabs.stories.ts

Comment thread tedi/components/navigation/tabs/tabs-list/tabs-list.component.ts Outdated
Comment thread tedi/components/navigation/tabs/tabs.spec.ts
Comment thread tedi/components/navigation/tabs/tabs.spec.ts Outdated
Comment thread tedi/components/navigation/tabs/tabs.stories.ts Outdated
Comment thread tedi/components/navigation/tabs/tabs-list/tabs-list.component.scss Outdated
Comment thread tedi/components/navigation/tabs/tabs.stories.ts
Comment thread tedi/components/navigation/tabs/tabs.stories.ts
Comment thread tedi/components/navigation/tabs/tabs.stories.ts
Comment thread tedi/components/navigation/tabs/tabs.stories.ts
@mart-sessman
mart-sessman merged commit 5f37a32 into rc Jun 30, 2026
20 checks passed
@mart-sessman
mart-sessman deleted the feat/14-tabs-new-tedi-ready branch June 30, 2026 11:40
github-actions Bot pushed a commit that referenced this pull request Jun 30, 2026
# [7.0.0-rc.2](angular-7.0.0-rc.1...angular-7.0.0-rc.2) (2026-06-30)

### Features

* **tabs:** new tedi-ready component [#14](#14) ([#481](#481)) ([5f37a32](5f37a32))
github-actions Bot pushed a commit that referenced this pull request Jul 2, 2026
# [7.0.0](angular-6.4.0...angular-7.0.0) (2026-07-02)

### Bug Fixes

* **date-field,date-picker:** resolved conflict with formcontrol [#494](#494) ([#501](#501)) ([7721071](7721071))
* **dropdown:** overridden browser-default padding on dropdown-content [#498](#498) ([#499](#499)) ([1219cde](1219cde))
* **icon:** size input now works inside buttons and links [#435](#435) ([#497](#497)) ([e2b6a70](e2b6a70))
* **table:** state is correctly forwarded + added state docs [#477](#477) ([#478](#478)) ([9282b60](9282b60))

### Features

* **accordion:** fix mobile examples, add new inputs and stories [#467](#467) ([#483](#483)) ([c45e3e7](c45e3e7))
* Added angular v22 support [#466](#466) ([#476](#476)) ([36b1266](36b1266))
* **alert:** add tedi-alert-action slot [#460](#460) ([#461](#461)) ([ca8fc86](ca8fc86))
* **alert:** Added small size [#502](#502) ([#503](#503)) ([c6bd5aa](c6bd5aa))
* **button-group:** new tedi-ready component [#9](#9) ([#450](#450)) ([37a4d3b](37a4d3b))
* **card,card-button,timeline-card:** new tedi-ready components [#453](#453) ([#479](#479)) ([7c13043](7c13043))
* **date-field,calendar:** calendar tedi-ready [#6](#6) ([#443](#443)) ([467271a](467271a))
* **dropdown:** Added support for wrapped buttons [#468](#468) ([#469](#469)) ([056340a](056340a))
* **ellipsis:** new tedi-ready component [#472](#472) ([#475](#475)) ([a38d594](a38d594))
* **float-ui:** replaced float-ui usage in relevant components [#380](#380) ([#401](#401)) ([7aee67b](7aee67b))
* **header:** update Header component against Figma [#312](#312) ([#440](#440)) ([81b1c18](81b1c18))
* **info-button:** added inverted variant [#236](#236) ([#496](#496)) ([0a67fa8](0a67fa8))
* **pagination:** tedi-ready component [#446](#446) ([#447](#447)) ([47af78b](47af78b))
* **progressbar,attachment:** new tedi-ready components [#253](#253) ([#451](#451)) ([b2b9b5b](b2b9b5b)), closes [#482](#482)
* **select:** added tooltip, ariaLabelledby, ariaLabel [#508](#508) ([#509](#509)) ([0ee3572](0ee3572))
* **table:** added new features [#480](#480) ([#485](#485)) ([1ca8a2d](1ca8a2d))
* **table:** added selectedRowHighlight input and updated stories [#445](#445) ([c7aeb1b](c7aeb1b))
* **table:** behavioural improvements [#470](#470) ([#473](#473)) ([098a616](098a616))
* **table:** new tedi-ready component [#445](#445) ([#448](#448)) ([2d9480e](2d9480e))
* **tabs:** new tedi-ready component [#14](#14) ([#481](#481)) ([5f37a32](5f37a32))
* **time-field,time-picker,scroll-fade:** new tedi-ready components [#374](#374) ([#397](#397)) ([0040e62](0040e62))

### BREAKING CHANGES

* **icon:** button and link icon size changed, tedi-icon--size-* overrides no longer work
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.

3 participants