Repository navigation
fix(BBBToggle): show keyboard focus and disabled state; add tooltip - #118
Merged
Arthurk12 merged 4 commits intoNov 12, 2026
Merged
Conversation
When BBBToggle is focused from the keyboard, MUI's focus ripple only tints the small thumb. That faint halo is the only focus cue, which falls short of WCAG 2.4.7 (Focus Visible). Draw a 2px colorBrand1 outline, offset by 2px, around the switch while it holds `.Mui-focusVisible`, the same treatment BBButton and BBBCheckbox use, so mouse clicks don't show it. The outline goes on the switch root because the track is clipped by the root's overflow. The root gets the track's border radius only while focused: a permanent radius would clip the track's anti-aliased edge a second time and slightly change how an unfocused toggle renders.
The component does not pass `disabled` to its text. With `disabled`, MUI dims the switch, but the label and helper text keep their regular colors and the text keeps `cursor: pointer`, so they look and point as if the toggle could still be changed. Destructure `disabled`, pass it on to the MUI switch and, as a transient `$disabled` prop, to the text wrapper, the label and the helper text. Disabled text gets `cursor: not-allowed` and colorNeutral3, the same color BBButton and BBBCheckbox use for disabled text. Also give the Storybook `disabled` control its default value, reword it and the README row to mention the dimmed text, and add a Disabled story.
A disabled BBBToggle in the on state looks enabled: its track stays at full brand color. The checked track's `opacity: 1` override outranks the opacity MUI applies to a disabled track, so only the unchecked track is dimmed. Restate MUI's disabled track opacity (0.12 in the light theme, 0.2 in the dark one) for a checked, disabled switch, so both states dim the same way. Add a DisabledChecked story.
Arthurk12
force-pushed
the
fix/toggle-focus-disabled
branch
from
November 10, 2026 01:20
7ec5fd8 to
6fa1e48
Compare
2 tasks done
germanocaumo
suggested changes
Nov 11, 2026
germanocaumo
left a comment
Contributor
There was a problem hiding this comment.
Focus ring, disabled styling, the dimmed checked track and the new tooltip triggers check out on MUI 6.4.9, 6.5.0 and 7.3.4 in Chromium, Firefox and WebKit (the tooltip stays up from text to switch and skips the empty full-width row). The tooltip has the same three issues #117 just fixed; the same changes apply.
germanocaumo
approved these changes
Nov 12, 2026
germanocaumo
left a comment
Contributor
There was a problem hiding this comment.
verified and working
BBBToggle has no way to show a tooltip. When a toggle is disabled, users get no explanation of why they can't change it. BBButton, BBBAccordion and BBBCheckbox already offer this through `tooltipLabel` and `tooltipPlacement`. Add the same two props, backed by Tippy and wired as in BBBCheckbox. Unlike BBBCheckbox's container, the toggle's wrapper spans the whole row, so it can't trigger or anchor the tooltip: the tooltip would open over empty space and center on the row. The text and the switch root trigger it instead, and it points at the text, or at the switch when there is no text. A 100ms hide delay bridges the gap between the text and the switch, so crossing it doesn't hide and reshow the tooltip. Tippy is rendered beside the wrapper and pointed at it through `reference`, instead of wrapping it: wrapping would change the root element whenever `tooltipLabel` is added or removed, and React would remount the toggle, dropping its focus and resetting an uncontrolled toggle to `defaultChecked`. The switch root is looked up through MUI's `switchClasses.root`: the Switch ref points at its inner button, which a disabled switch hides from the pointer with `pointer-events: none`. Passing a ref through `slotProps.root` was discarded, as it could override a consumer's own root slot props. The tooltip opens on `mouseenter` and `focusin`, because `focusin` bubbles up from the input and Tippy's `focus` trigger does not. The tooltip text is also kept in a `hidden` element that the input's `aria-describedby` points to, after the helper text or `ariaDescribedBy`, since Tippy only mounts its content while the tooltip is shown. A visually hidden copy was discarded: it is still page text, so screen readers would read the tooltip twice in browse mode. When nothing else names the toggle (no `label`, `ariaLabel`, `ariaLabelledBy` or `helperText`), the tooltip text names it through `aria-labelledby` instead of describing it, so a toggle with only a tooltip still has an accessible name. A natively disabled input leaves the tab order, so keyboard users could never reach the tooltip that explains why it is disabled. When `disabled` and `tooltipLabel` are both set, the input gets `aria-disabled="true"` instead of the native `disabled` attribute and stays focusable: - the MUI switch still receives `disabled`, so it keeps its disabled look; - an `onClick` with `preventDefault()` on the switch cancels mouse clicks, label clicks and Space, and MUI skips `onChange` for a prevented click. It sits on the switch because MUI drops event handlers passed through `slotProps.input`, except `onChange`; - `name` and `required` are dropped from the input, so it stays out of form submission and validation, as a natively disabled input would; - MUI never sets `Mui-focusVisible` while disabled, so the focus outline also matches `.Mui-disabled input:focus-visible`. Without a tooltip, a disabled toggle keeps the native `disabled` attribute and leaves the tab order, as before.
Arthurk12
force-pushed
the
fix/toggle-focus-disabled
branch
from
November 12, 2026 18:22
0180879 to
5de4152
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
BBBTogglenow shows keyboard focus and a dimmed disabled state, and gains a tooltip, matching the recentBBBCheckboxchanges.BBButtonandBBBCheckbox.disabled, the label and helper text are dimmed and show a not-allowed cursor.tooltipLabelandtooltipPlacement(topby default,bottom,left,right) props show a tooltip on hover and keyboard focus.tooltipLabelstays reachable with Tab, so keyboard users can read why it is unavailable. It is announced as unavailable, can't be toggled, and is left out of form submission and validation, like a natively disabled toggle.disabled,tooltipLabelandtooltipPlacement.Motivation
Keyboard focus is only a faint halo on the thumb, a disabled toggle's text still looks clickable, and a disabled toggle that is on looks enabled. A disabled toggle also has no way to tell users why it is unavailable.
More