From cd1753c346100772dc5677b0d047118da1ac5627 Mon Sep 17 00:00:00 2001 From: Kalpana Chavhan Date: Thu, 1 Jan 2026 22:36:38 +0530 Subject: [PATCH 1/2] fix(a11y): add dev warning for buttons missing accessible names --- .../fuselage/src/components/Button/Button.tsx | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/fuselage/src/components/Button/Button.tsx b/packages/fuselage/src/components/Button/Button.tsx index 37853eb4ee..ad0b3da854 100644 --- a/packages/fuselage/src/components/Button/Button.tsx +++ b/packages/fuselage/src/components/Button/Button.tsx @@ -1,5 +1,5 @@ import type { AllHTMLAttributes } from 'react'; -import { forwardRef, useMemo } from 'react'; +import { forwardRef, useMemo, Children } from 'react'; import { Box, type BoxProps } from '../Box'; import { Icon, type IconProps } from '../Icon'; @@ -83,6 +83,22 @@ const Button = forwardRef( return {}; }, [primary, secondary, danger, warning, success]); + // --- Accessibility Check (Dev Only) --- + if (process.env.NODE_ENV !== 'production') { + const childrenArray = Children.toArray(children); + const hasTextContent = childrenArray.some( + (child) => typeof child === 'string' && child.trim().length > 0 + ); + + const isVisualOnly = !hasTextContent && (!!icon || !!loading || square); + + if (isVisualOnly && !props['aria-label'] && !props['aria-labelledby']) { + console.warn( + `Fuselage [Button]: Buttons without visible text (icon-only or square buttons) must provide an 'aria-label' or 'aria-labelledby' prop for accessibility.` + ); + } + } + return ( ( }, ); -export default Button; +export default Button; \ No newline at end of file From d4cc450794085b6fca105216f9f18b5d958cdc65 Mon Sep 17 00:00:00 2001 From: Kalpana Chavhan Date: Fri, 2 Jan 2026 11:58:08 +0530 Subject: [PATCH 2/2] fix(fuselage): add button a11y warning and default type='button' --- .../fuselage/src/components/Button/Button.tsx | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/fuselage/src/components/Button/Button.tsx b/packages/fuselage/src/components/Button/Button.tsx index ad0b3da854..eadc93df2a 100644 --- a/packages/fuselage/src/components/Button/Button.tsx +++ b/packages/fuselage/src/components/Button/Button.tsx @@ -39,6 +39,7 @@ const Button = forwardRef( external, icon, is = 'button', + type = 'button', // Defaulting to 'button' here for safety rel: _rel, tiny, mini, @@ -53,15 +54,20 @@ const Button = forwardRef( }, ref, ) { - const extraProps = - (is === 'a' && { - rel: external ? 'noopener noreferrer' : undefined, - target: external ? '_blank' : undefined, - }) || - (is === 'button' && { - type: 'button', - }) || - {}; + const extraProps = useMemo(() => { + if (is === 'a') { + return { + rel: external ? 'noopener noreferrer' : undefined, + target: external ? '_blank' : undefined, + }; + } + + if (is === 'button') { + return { type }; // Uses the 'type' prop (default 'button') + } + + return {}; + }, [is, external, type]); const kindAndVariantProps = useMemo(() => { const variant = @@ -102,7 +108,6 @@ const Button = forwardRef( return (