diff --git a/packages/gamut/src/DataList/Controls/ExpandControl.tsx b/packages/gamut/src/DataList/Controls/ExpandControl.tsx index 657fc45c57..f908870dbe 100644 --- a/packages/gamut/src/DataList/Controls/ExpandControl.tsx +++ b/packages/gamut/src/DataList/Controls/ExpandControl.tsx @@ -32,6 +32,8 @@ export const ExpandControl: React.FC = ({ }} aria-label={`Expand ${id} Row`} aria-expanded={expanded} + // REVISIT THIS + aria-controls={id ?? undefined} > diff --git a/packages/gamut/src/DataList/Tables/Rows/TableRow.tsx b/packages/gamut/src/DataList/Tables/Rows/TableRow.tsx index 38784942c4..0db757f2b8 100644 --- a/packages/gamut/src/DataList/Tables/Rows/TableRow.tsx +++ b/packages/gamut/src/DataList/Tables/Rows/TableRow.tsx @@ -70,6 +70,7 @@ export const TableRow: DataRow = ({ return ( = ({ variant, }) => { const [isExpanded, setIsExpanded] = useState(initiallyExpanded); + return ( onClick?.()} - as={isListItem ? 'li' : undefined} + variant={variant} > {isExpanded && ( )} diff --git a/packages/gamut/src/Drawer/index.tsx b/packages/gamut/src/Drawer/index.tsx index 36796f6078..5839b4d599 100644 --- a/packages/gamut/src/Drawer/index.tsx +++ b/packages/gamut/src/Drawer/index.tsx @@ -20,12 +20,19 @@ export interface DrawerProps extends Omit { * Which edge of the drawer content container is aligned to during the animation. */ alignContentContainer?: 'left' | 'right'; + // REVISIT THIS + /** + * This `id` is used to link the element that expands the Drawer to the Drawer itself. + * It is needed for the `aria-controls` attribute to work properly for accessibility. + */ + id: string; } export const Drawer: React.FC = ({ + alignContentContainer = 'right', children, expanded, - alignContentContainer = 'right', + id, ...props }) => { const drawerRef = useRef(null); @@ -41,9 +48,9 @@ export const Drawer: React.FC = ({ {expanded ? ( = ({ + bg = 'background', children, closeLabel = 'Close', + id, expanded, openFrom = 'left', onClose, title, - bg = 'background', }) => { return ( = ({ > >> { header?: boolean; + // REVISIT THIS + /** Used to link expandable content with the component that does the expanding, i.e. it's used to set the value for aria-controls */ + id?: string; /** This is an internal prop that is largely only used for the DataTable component */ numOfColumns?: number; /** This is an internal prop that is largely only used for the DataTable component */ @@ -45,12 +48,13 @@ const DivExpand = styled(motion.div)(expandStyles); const TDExpand = styled(motion.td)(expandStyles); const ExpandInCollapseOut: React.FC< - WithChildrenProp & { as: 'td' | 'div' } -> = ({ as, children }) => { + WithChildrenProp & { as: 'td' | 'div'; id: string | undefined } +> = ({ as, children, id }) => { const ResponsiveExpand = as === 'td' ? TDExpand : DivExpand; return ( ( ( { + id, children, expanded, expandedRowAriaLabel, @@ -101,6 +106,8 @@ export const ListRow = forwardRef( ( {content} {expanded && ( - + {renderExpanded?.()} diff --git a/packages/gamut/src/Tip/InfoTip/index.tsx b/packages/gamut/src/Tip/InfoTip/index.tsx index 61eb5095a9..e0c52bb0f3 100644 --- a/packages/gamut/src/Tip/InfoTip/index.tsx +++ b/packages/gamut/src/Tip/InfoTip/index.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState } from 'react'; +import { useEffect, useId, useRef, useState } from 'react'; import { FloatingTip } from '../shared/FloatingTip'; import { InlineTip } from '../shared/InlineTip'; @@ -88,6 +88,8 @@ export const InfoTip: React.FC = ({ const Tip = loaded && isFloating ? FloatingTip : InlineTip; + const textId = useId(); + const tipProps = { alignment, escapeKeyPressHandler, @@ -101,14 +103,18 @@ export const InfoTip: React.FC = ({ {!isTipHidden ? info : `\xa0`} ); + // REVISIT THIS const tip = ( clickHandler()} diff --git a/packages/styleguide/src/lib/Atoms/Drawer/Drawer.mdx b/packages/styleguide/src/lib/Atoms/Drawer/Drawer.mdx index cb78a1e64b..2d7356761f 100644 --- a/packages/styleguide/src/lib/Atoms/Drawer/Drawer.mdx +++ b/packages/styleguide/src/lib/Atoms/Drawer/Drawer.mdx @@ -34,6 +34,32 @@ An example of a molecule that uses Drawer is the F Our Drawers are [controlled components](https://reactjs.org/docs/forms.html#controlled-components), so their checked value must be controlled by an external state passed in as `expanded`. +{/* REVISIT THIS */} +The component that toggles the `Drawer` should include both `aria-expanded` and `aria-controls` attributes. The `aria-controls` attribute must reference the `id` of the `Drawer`. The `aria-expanded` attribute should reflect the value of the `expanded` prop passed to the `Drawer`. + +```tsx +const ExampleDrawer: React.FC = () => { + const [expanded, setExpanded] = useState(false); + const drawerId = useId(); + + return ( + + + Example Drawer + + setExpanded((previousExpanded) => !previousExpanded)} + > + Set the proper aria-labels! + + + ); +}; +``` + ## Playground diff --git a/packages/styleguide/src/lib/Atoms/Drawer/Drawer.stories.tsx b/packages/styleguide/src/lib/Atoms/Drawer/Drawer.stories.tsx index acfb94e4bc..8a85823e56 100644 --- a/packages/styleguide/src/lib/Atoms/Drawer/Drawer.stories.tsx +++ b/packages/styleguide/src/lib/Atoms/Drawer/Drawer.stories.tsx @@ -1,6 +1,6 @@ import { Drawer, FlexBox, StrokeButton } from '@codecademy/gamut'; import type { Meta } from '@storybook/react'; -import { useState } from 'react'; +import { useId, useState } from 'react'; const meta: Meta = { component: Drawer, @@ -11,10 +11,17 @@ export default meta; export const Default: React.FC = () => { const [expanded, setExpanded] = useState(false); + const drawerId = useId(); return ( - Drawer content in here! + {/* // REVISIT THIS */} + + Drawer content in here! + setExpanded((previousExpanded) => !previousExpanded)} > Toggle Drawer diff --git a/packages/styleguide/src/lib/Molecules/Flyout/Flyout.mdx b/packages/styleguide/src/lib/Molecules/Flyout/Flyout.mdx index 81c1bb925b..a2eee7ed99 100644 --- a/packages/styleguide/src/lib/Molecules/Flyout/Flyout.mdx +++ b/packages/styleguide/src/lib/Molecules/Flyout/Flyout.mdx @@ -28,7 +28,33 @@ On button click, a container animates in from the left or right side of the wind Internally, Flyout is a combination of Overlay and Drawer. -Our Flyouts are [controlled components](https://reactjs.org/docs/forms.html#controlled-components), so their checked value must be controlled by an external state passed in as `expanded` and `onChange`: +Our Flyouts are [controlled components](https://reactjs.org/docs/forms.html#controlled-components), so their checked value must be controlled by an external state passed in as `expanded` and `onChange`. + +{/* // REVISIT THIS */} +The component that toggles the `Flyout` should include both `aria-expanded` and `aria-controls` attributes. The `aria-controls` attribute must reference the `id` of the `Flyout`. The `aria-expanded` attribute should reflect the value of the `expanded` prop passed to the `Flyout`. + +```tsx +const ExampleFlyout: React.FC = () => { + const [expanded, setExpanded] = useState(false); + const flyoutId = useId(); + + return ( + + + Example Flyout + + setExpanded((previousExpanded) => !previousExpanded)} + > + Set the proper aria-labels! + + + ); +}; +``` ## Playground diff --git a/packages/styleguide/src/lib/Molecules/Flyout/Flyout.stories.tsx b/packages/styleguide/src/lib/Molecules/Flyout/Flyout.stories.tsx index 0d7d229340..53a5de796a 100644 --- a/packages/styleguide/src/lib/Molecules/Flyout/Flyout.stories.tsx +++ b/packages/styleguide/src/lib/Molecules/Flyout/Flyout.stories.tsx @@ -5,7 +5,9 @@ import { useState } from 'react'; const meta: Meta = { component: Flyout, - args: {}, + args: { + id: 'flyout-example', + }, }; export default meta; @@ -35,7 +37,12 @@ export const FlyoutExample: Story = { hurricane... - setExpanded(true)}> + setExpanded(true)} + > Tell me more?! diff --git a/packages/styleguide/src/lib/Organisms/Lists & Tables/List/List.mdx b/packages/styleguide/src/lib/Organisms/Lists & Tables/List/List.mdx index 1740c8606d..f84977ffeb 100644 --- a/packages/styleguide/src/lib/Organisms/Lists & Tables/List/List.mdx +++ b/packages/styleguide/src/lib/Organisms/Lists & Tables/List/List.mdx @@ -216,6 +216,9 @@ You can define collapsible content by passing an `expanded` prop and the `React. #### Expand on button click +The `ListRow` component has access to the `ExpandControl` component which can be used to toggle the expanded state of the row. The `ExpandControl` component will automatically handle the rotation of the icon based on the expanded state. +Ensure that the `ListRow` has a unique `id` prop to ensure that the `ExpandControl` can set the correct aria attributes. + ```tsx export const ExpandableRow: React.FC<{ header: string; @@ -226,6 +229,7 @@ export const ExpandableRow: React.FC<{ return ( Surprise} @@ -233,11 +237,12 @@ export const ExpandableRow: React.FC<{ {header} {content} - setExpanded(!isExpanded)}> - - - - + setExpanded(!isExpanded)} + id={idOfRow} + disabled={false} + /> ); @@ -246,6 +251,8 @@ export const ExpandableRow: React.FC<{ #### Expand on row click +Make sure you pass in an `id` prop to the `ListRow` component so that the correct aria attributes are set on the row. + ```tsx export const ExpandableRow: React.FC<{ header: string; @@ -256,6 +263,7 @@ export const ExpandableRow: React.FC<{ return ( setExpanded(!isExpanded)} @@ -291,15 +299,15 @@ You can combine variants and spacing to your needs. -### Expandable buttom +### Expandable button -Buttons can be configured to expand the row content. +Buttons can be configured to expand the row content. Check over the "Expand on button click" section for more guidance. ### Expanded row -An entire row can be made interactive to expand the row content. +An entire row can be made interactive to expand the row content. Check over the "Expand on row click" section for more guidance. diff --git a/packages/styleguide/src/lib/Organisms/Lists & Tables/List/List.stories.tsx b/packages/styleguide/src/lib/Organisms/Lists & Tables/List/List.stories.tsx index 8133db2e64..324141b65e 100644 --- a/packages/styleguide/src/lib/Organisms/Lists & Tables/List/List.stories.tsx +++ b/packages/styleguide/src/lib/Organisms/Lists & Tables/List/List.stories.tsx @@ -1,5 +1,6 @@ import { Box, + ExpandControl, FillButton, FlexBox, IconButton, @@ -14,7 +15,6 @@ import { import { ArrowChevronDownIcon, HouseEntranceIcon, - MiniChevronDownIcon, MiniDeleteIcon, MiniKebabMenuIcon, StarIcon, @@ -648,6 +648,7 @@ const ExpandableButtonClickRow: React.FC<{ return ( } @@ -655,11 +656,12 @@ const ExpandableButtonClickRow: React.FC<{ Hail - setExpanded(!isExpanded)}> - - - - + setExpanded(!isExpanded)} + id={`${name}-${role}-${ship}`} + disabled={false} + /> ); @@ -699,6 +701,7 @@ export const ExpandableRowClick: React.FC = ({ expanded={isExpanded} key={key} onClick={() => setExpanded(!isExpanded)} + id={`${name}-${role}-${ship}`} renderExpanded={() => } >