Skip to content

fix(tabs): move the indicator when the text direction changes - #223

Merged
ndlabdev merged 2 commits into
devfrom
fix/216-tabs-direction
Sep 18, 2026
Merged

ndlabdev merged 2 commits into
devfrom
fix/216-tabs-direction

Conversation

@ndlabdev

Copy link
Copy Markdown
Owner

Summary

Tabs positions its sliding indicator from the active trigger's offset, and recomputed it only when value, orientation or items changed, or when the list resized. Flipping the text direction at runtime, for example a language switch that turns the page from ltr to rtl, mirrors the triggers without any of those, so the indicator kept its old offset and ended up under a different tab. The active label still rendered in the on-indicator color over the plain background, which made it look unreadable.

The indicator is now recomputed whenever a dir attribute changes in the document.

Closes #216

Type of change

  • 🐛 Bug fix
  • ✨ New feature / component
  • 📖 Documentation
  • ♻️ Refactor / chore
  • ⚠️ Breaking change

Changes

  • Tabs observes dir attribute changes (attributeFilter: ['dir'], subtree: true, from the document element) and reuses the existing rAF-debounced update. Watching the whole document rather than the current [dir] ancestors also covers a dir added to an ancestor later.
  • The observer is disconnected on destroy, together with the pending animation frame.
  • Small tidy in the same block: querySelector<HTMLElement> instead of a cast, and one cleanup instead of two.
  • One regression test in the existing spec, without fixture files: with the first tab active, flipping the container to rtl and back keeps the indicator's left and width on the active trigger. It fails on dev (indicator at 4px while the trigger moved to 852px).
  • CHANGELOG.md entry under [Unreleased].

Checklist

  • Linked the related issue (Closes #…)
  • pnpm check passes (0 errors, 0 warnings)
  • pnpm lint passes
  • pnpm test passes
  • Added or updated tests for the change
  • Updated CHANGELOG.md under [Unreleased]
  • Followed component conventions (no comments outside *.types.ts, Material 3 design tokens)

Screenshots / notes

Verified in Chromium against dev, with the first tab active and a three-tab list:

  • dir toggled on a wrapper element (the snippet from the issue): the active trigger moves from 4px to 459px. On dev the indicator stays at 4px; with the fix it follows to 459px and back.
  • dir toggled on the html element, as a language switch would: same result.

Known limit: a direction set only through CSS, for example a class that applies direction: rtl, is not detected, since there is no attribute change to observe. The issue notes the same limit.

NavigationMenu measures its highlight bar the same way, but it is not affected: its root carries dir="ltr", so a wrapper flipping to rtl does not mirror it.

Only verified in Chromium.

The sliding indicator was positioned from the active trigger's offset,
and only recomputed when the value, orientation or items changed, or
when the list resized. Flipping the page from ltr to rtl mirrors the
triggers without any of those, so the indicator kept its old offset and
sat under the wrong tab, with the active label rendered in the on
indicator color over the plain background.

The indicator is now recomputed when a dir attribute changes anywhere in
the document. A direction set only through CSS is still not detected.

Closes #216
@ndlabdev ndlabdev added the bug Something isn't working label Sep 18, 2026
@ndlabdev ndlabdev self-assigned this Sep 18, 2026
@ndlabdev
ndlabdev merged commit f54c329 into dev Sep 18, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant