From a6b84e13ec7e55b09950c97f8d2911317d6c6d32 Mon Sep 17 00:00:00 2001 From: Johan Persson Date: Tue, 17 Mar 2026 12:02:49 +0100 Subject: [PATCH] fix(ui): make Checkbox children optional with a11y warning Made children optional and only render the label wrapper div when children are provided. When used without children, a dev warning is shown if no aria-label or aria-labelledby is set. Signed-off-by: Johan Persson --- .changeset/fix-checkbox-empty-label-gap.md | 7 +++++++ packages/ui/report.api.md | 2 +- packages/ui/src/components/Checkbox/Checkbox.tsx | 14 ++++++++++++-- packages/ui/src/components/Checkbox/types.ts | 2 +- 4 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 .changeset/fix-checkbox-empty-label-gap.md diff --git a/.changeset/fix-checkbox-empty-label-gap.md b/.changeset/fix-checkbox-empty-label-gap.md new file mode 100644 index 0000000000..323d8e7bab --- /dev/null +++ b/.changeset/fix-checkbox-empty-label-gap.md @@ -0,0 +1,7 @@ +--- +'@backstage/ui': patch +--- + +Made Checkbox `children` optional and added a dev warning when neither a visible label, `aria-label`, nor `aria-labelledby` is provided. The label wrapper div is no longer rendered when there are no children, removing the unnecessary gap. + +**Affected components:** Checkbox diff --git a/packages/ui/report.api.md b/packages/ui/report.api.md index 0b11df6055..364592a6ff 100644 --- a/packages/ui/report.api.md +++ b/packages/ui/report.api.md @@ -839,7 +839,7 @@ export const CheckboxDefinition: { // @public (undocumented) export type CheckboxOwnProps = { - children: React.ReactNode; + children?: React.ReactNode; className?: string; }; diff --git a/packages/ui/src/components/Checkbox/Checkbox.tsx b/packages/ui/src/components/Checkbox/Checkbox.tsx index d7b0bd6f76..84a420ad8b 100644 --- a/packages/ui/src/components/Checkbox/Checkbox.tsx +++ b/packages/ui/src/components/Checkbox/Checkbox.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { forwardRef } from 'react'; +import { forwardRef, useEffect } from 'react'; import { Checkbox as RACheckbox } from 'react-aria-components'; import type { CheckboxProps } from './types'; import { useDefinition } from '../../hooks/useDefinition'; @@ -29,6 +29,16 @@ export const Checkbox = forwardRef( props, ); const { classes, children } = ownProps; + const ariaLabel = restProps['aria-label']; + const ariaLabelledBy = restProps['aria-labelledby']; + + useEffect(() => { + if (!children && !ariaLabel && !ariaLabelledBy) { + console.warn( + 'Checkbox requires either a visible label, aria-label, or aria-labelledby for accessibility', + ); + } + }, [children, ariaLabel, ariaLabelledBy]); return ( ( )} -
{children}
+ {children != null &&
{children}
} )}
diff --git a/packages/ui/src/components/Checkbox/types.ts b/packages/ui/src/components/Checkbox/types.ts index d9b220eb2a..5cdef0e423 100644 --- a/packages/ui/src/components/Checkbox/types.ts +++ b/packages/ui/src/components/Checkbox/types.ts @@ -17,7 +17,7 @@ import type { CheckboxProps as RACheckboxProps } from 'react-aria-components'; /** @public */ export type CheckboxOwnProps = { - children: React.ReactNode; + children?: React.ReactNode; className?: string; };