Repository navigation
Conversation
StyledCheckbox sets `padding: 0` on the MUI root, so MUI's focus ripple only tints the inside of the box. On a light background that is a faint grey square, and nothing else marks keyboard focus, which falls short of WCAG 2.4.7 (Focus Visible). Draw a 2px colorBrand1 outline, offset by 2px, on `.Mui-focusVisible`, matching the color BBButton uses for its focus outline. Keying it on `.Mui-focusVisible` instead of `:focus` keeps the outline off for mouse clicks. The root's border radius follows the shape of the control (borderRadiusSmall for the square box, 50% for the round variant), so the outline traces the box instead of MUI's default circle. Restoring MUI's 9px padding was discarded: it would bring back a 39px ripple halo and change the checkbox's layout footprint for every consumer. Refs bigbluebutton#108
…sabled The component does not pass `disabled` to its Label, which always has `cursor: pointer` and the default text color. With `disabled`, MUI dims the box, but the label still looks and points as if it were clickable. Destructure `disabled`, pass it on to the MUI checkbox and, as a transient `$disabled` prop, to the Label. A disabled label gets `cursor: not-allowed` and colorNeutral3, the same color BBButton uses for disabled text. The label is built once and placed according to `layout`, instead of being duplicated per layout. Also document `disabled` in the Storybook controls and in the README props table, and add a Disabled story. Refs bigbluebutton#108
BBBCheckbox has no way to show a tooltip. When a checkbox is disabled, users get no explanation of why they can't change it. BBButton and BBBAccordion already offer this through `tooltipLabel` and `tooltipPlacement`. Add the same two props, backed by Tippy like the other components. The tooltip is attached to the container around the box and the label, not to the input: MUI gives a disabled box `pointer-events: none`, so hovering it reaches the container. It 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 visually hidden element that the input's `aria-describedby` points to, since Tippy only mounts its content while the tooltip is shown. 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 checkbox still receives `disabled`, so the box keeps its disabled look; - an `onClick` with `preventDefault()` on the checkbox root cancels mouse clicks, label clicks and Space, and MUI skips `onChange` for a prevented click. It sits on the root 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. Without that, a required, unchecked, aria-disabled checkbox would block its form from being submitted; - MUI never sets `Mui-focusVisible` while disabled, so the focus outline matches it through `.Mui-disabled:has(input:focus-visible)`. Without a tooltip, a disabled checkbox keeps the native `disabled` attribute and leaves the tab order, as before. Making the container focusable was discarded: focus would land on an element with no role or name, which screen readers announce poorly. Refs bigbluebutton#108
BBBCheckbox has no way to show secondary text under its label, which BBBToggle offers through `helperText`. Consumers that need a short explanation next to a checkbox have to lay it out themselves. Add `helperText`, rendered below the label in fontSizeSmall and colorTextLight (one step below the label, as in BBBToggle), and dimmed like the label when disabled. The container turns from an inline flex row into an inline grid, with the box and the label on the first row and the helper text on the second, under the label. In a flex row, the box would be centered on the whole two-line text block instead of on the label's line. With the `left` layout, the text is aligned to the end, next to the box. Layouts without helper text render the same as before. The helper text is a second <label> for the input, so clicking it toggles the checkbox, as clicking the label does; in a disabled checkbox the click does nothing. Every associated <label> joins the accessible name, which would read the helper text twice. When there is a label, the input's aria-labelledby points at the label alone and aria-describedby at the helper text, followed by the tooltip text when `tooltipLabel` is set. With no label or `ariaLabel`, the helper text names the checkbox and is left out of the description. BBBToggle uses the same rule. Also document `helperText` in the Storybook controls and in the README, and add stories with the helper text on each side.
germanocaumo
suggested changes
Nov 10, 2026
germanocaumo
left a comment
Contributor
There was a problem hiding this comment.
Checked the focus ring, disabled styling, the aria-disabled path (no toggle on click/label/helper/Space, left out of form data and validation) and names/descriptions in Chromium, Firefox and WebKit on MUI 6.4.9, 6.5.0 and 7.3.4. All good apart from the inline notes.
For the description: a wrapped label with layout="left" is now right-aligned and the hover tint is a rounded square, so "render as before" isn't quite exact (both look fine).
feat(BBBCheckbox): add tooltipLabel and tooltipPlacement props BBBCheckbox has no way to show a tooltip. When a checkbox is disabled, users get no explanation of why they can't change it. BBButton and BBBAccordion already offer this through `tooltipLabel` and `tooltipPlacement`. Add the same two props, backed by Tippy like the other components. The tooltip is attached to the container around the box and the label, not to the input: MUI gives a disabled box `pointer-events: none`, so hovering it reaches the container. It opens on `mouseenter` and `focusin`, because `focusin` bubbles up from the input and Tippy's `focus` trigger does not. Tippy is rendered beside the container 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 checkbox, dropping its focus and resetting an uncontrolled checkbox to `defaultChecked`. The tooltip text is also kept in a `hidden` element that the input's `aria-describedby` points to, 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. 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 checkbox still receives `disabled`, so the box keeps its disabled look; - an `onClick` with `preventDefault()` on the checkbox root cancels mouse clicks, label clicks and Space, and MUI skips `onChange` for a prevented click. It sits on the root 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. Without that, a required, unchecked, aria-disabled checkbox would block its form from being submitted; - MUI never sets `Mui-focusVisible` while disabled, so the focus outline matches it through `.Mui-disabled:has(input:focus-visible)`. Without a tooltip, a disabled checkbox keeps the native `disabled` attribute and leaves the tab order, as before. Making the container focusable was discarded: focus would land on an element with no role or name, which screen readers announce poorly. Refs bigbluebutton#108
feat(BBBCheckbox): add tooltipLabel and tooltipPlacement props BBBCheckbox has no way to show a tooltip. When a checkbox is disabled, users get no explanation of why they can't change it. BBButton and BBBAccordion already offer this through `tooltipLabel` and `tooltipPlacement`. Add the same two props, backed by Tippy like the other components. The tooltip is attached to the container around the box and the label, not to the input: MUI gives a disabled box `pointer-events: none`, so hovering it reaches the container. It opens on `mouseenter` and `focusin`, because `focusin` bubbles up from the input and Tippy's `focus` trigger does not. Tippy is rendered beside the container 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 checkbox, dropping its focus and resetting an uncontrolled checkbox to `defaultChecked`. The tooltip text is also kept in a `hidden` element that the input's `aria-describedby` points to, 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 checkbox (no `label` or `ariaLabel`), the tooltip text names it through `aria-labelledby` instead of describing it, so a checkbox 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 checkbox still receives `disabled`, so the box keeps its disabled look; - an `onClick` with `preventDefault()` on the checkbox root cancels mouse clicks, label clicks and Space, and MUI skips `onChange` for a prevented click. It sits on the root 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. Without that, a required, unchecked, aria-disabled checkbox would block its form from being submitted; - MUI never sets `Mui-focusVisible` while disabled, so the focus outline matches it through `.Mui-disabled:has(input:focus-visible)`. Without a tooltip, a disabled checkbox keeps the native `disabled` attribute and leaves the tab order, as before. Making the container focusable was discarded: focus would land on an element with no role or name, which screen readers announce poorly. Refs bigbluebutton#108
feat(BBBCheckbox): add helperText prop BBBCheckbox has no way to show secondary text under its label, which BBBToggle offers through `helperText`. Consumers that need a short explanation next to a checkbox have to lay it out themselves. Add `helperText`, rendered below the label in fontSizeSmall and colorTextLight (one step below the label, as in BBBToggle), and dimmed like the label when disabled. The container turns from an inline flex row into an inline grid, with the box and the label on the first row and the helper text on the second, under the label. In a flex row, the box would be centered on the whole two-line text block instead of on the label's line. With the `left` layout, the text is aligned to the end, next to the box, so a label that wraps onto several lines is now right-aligned even without helper text. The helper text is a second <label> for the input, so clicking it toggles the checkbox, as clicking the label does; in a disabled checkbox the click does nothing. Every associated <label> joins the accessible name, which would read the helper text twice. When there is a label, the input's aria-labelledby points at the label alone and aria-describedby at the helper text, followed by the tooltip text when `tooltipLabel` is set. With no label or `ariaLabel`, the helper text names the checkbox and is left out of the description, and the tooltip text, which would otherwise name it, stays in the description. BBBToggle uses the same rule. Also document `helperText` in the Storybook controls and in the README, and add stories with the helper text on each side.
2 tasks
This branch has not been deployed
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?
BBBCheckboxnow shows keyboard focus and a disabled label, and gains a tooltip and helper text.BBButton's focus outline.disabled, the label is dimmed and shows 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 checkbox.helperTextprop shows secondary text below the label. Clicking it toggles the checkbox, and screen readers read it as the checkbox's description.disabled,tooltipLabel,tooltipPlacementandhelperText.Closes Issue(s)
Closes #108
Motivation
Keyboard focus is only a faint tint inside the box, and a disabled checkbox's label still looks clickable (#108). A disabled checkbox also has no way to tell users why it is unavailable, and there is no helper text like
BBBToggle's.More
tooltipLabel/tooltipPlacementandhelperTextgo beyond BBBCheckbox: no visible keyboard focus, and the label ignores disabled #108, so they arefeatchanges and bump the minor version.