Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Utilize aria-describedby on all ActionList descriptions #4666

Merged
merged 14 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/lovely-days-march.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': patch
---

Adds `aria-describedby` to `ActionList` inline descriptions, adds `aria-labelledby` to `ActionList.TrailingVisual`
TylerJDev marked this conversation as resolved.
Show resolved Hide resolved
36 changes: 36 additions & 0 deletions packages/react/src/ActionList/ActionList.features.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Box from '../Box'
import Label from '../Label'
import Heading from '../Heading'
import {AnchoredOverlay} from '../AnchoredOverlay'
import CounterLabel from '../CounterLabel'
import {
EyeIcon,
BookIcon,
Expand All @@ -25,6 +26,9 @@ import {
PeopleIcon,
FileDirectoryIcon,
PlusCircleIcon,
GitPullRequestIcon,
IssueOpenedIcon,
ProjectIcon,
LinkExternalIcon,
} from '@primer/octicons-react'
import {FeatureFlags} from '../FeatureFlags'
Expand Down Expand Up @@ -726,6 +730,38 @@ export const GroupWithFilledTitle = () => {
)
}

export const WithCustomTrailingVisuals = () => (
<ActionList>
<ActionList.Item>
<ActionList.LeadingVisual>
<IssueOpenedIcon />
</ActionList.LeadingVisual>
Issues
<ActionList.TrailingVisual>
<CounterLabel>20</CounterLabel>
</ActionList.TrailingVisual>
</ActionList.Item>
<ActionList.Item>
<ActionList.LeadingVisual>
<GitPullRequestIcon />
</ActionList.LeadingVisual>
PRs
<ActionList.TrailingVisual>
<CounterLabel>12</CounterLabel>
</ActionList.TrailingVisual>
</ActionList.Item>
<ActionList.Item>
<ActionList.LeadingVisual>
<ProjectIcon />
</ActionList.LeadingVisual>
Projects
<ActionList.TrailingVisual>
<CounterLabel>2</CounterLabel>
</ActionList.TrailingVisual>
</ActionList.Item>
</ActionList>
)

export const ActionListWithButtonSemantics = () => {
return (
<FeatureFlags flags={{primer_react_action_list_item_as_button: true}}>
Expand Down
22 changes: 17 additions & 5 deletions packages/react/src/ActionList/Item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ export const Item = React.forwardRef<HTMLLIElement, ActionListItemProps>(
const labelId = `${itemId}--label`
const inlineDescriptionId = `${itemId}--inline-description`
const blockDescriptionId = `${itemId}--block-description`
const trailingVisualId = `${itemId}--trailing-visual`
const inactiveWarningId = inactive && !showInactiveIndicator ? `${itemId}--warning-message` : undefined

const ButtonItemWrapper = React.forwardRef(({as: Component = 'button', children, ...props}, forwardedRef) => {
Expand Down Expand Up @@ -294,10 +295,14 @@ export const Item = React.forwardRef<HTMLLIElement, ActionListItemProps>(
'data-inactive': inactive ? true : undefined,
'data-loading': loading && !inactive ? true : undefined,
tabIndex: disabled || showInactiveIndicator ? undefined : 0,
'aria-labelledby': `${labelId} ${slots.inlineDescription ? inlineDescriptionId : ''}`,
'aria-describedby': slots.blockDescription
? [blockDescriptionId, inactiveWarningId].join(' ')
: inactiveWarningId,
'aria-labelledby': `${labelId} ${slots.trailingVisual ? trailingVisualId : ''} ${
slots.inlineDescription ? inlineDescriptionId : ''
}`,
'aria-describedby':
TylerJDev marked this conversation as resolved.
Show resolved Hide resolved
[slots.blockDescription ? blockDescriptionId : undefined, inactiveWarningId ?? undefined]
.filter(String)
.join(' ')
.trim() || undefined,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: Don't think we need trim now that we are filtering strings

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this because we'd get aria-describedby=" " if none of the values were true. With the trim() || undefined, it will remove the attribute altogether since it's just an empty string at that point 🤔

...(includeSelectionAttribute && {[itemSelectionAttribute]: selected}),
role: itemRole,
id: itemId,
Expand Down Expand Up @@ -327,7 +332,14 @@ export const Item = React.forwardRef<HTMLLIElement, ActionListItemProps>(

return (
<ItemContext.Provider
value={{variant, disabled, inactive: Boolean(inactiveText), inlineDescriptionId, blockDescriptionId}}
value={{
variant,
disabled,
inactive: Boolean(inactiveText),
inlineDescriptionId,
blockDescriptionId,
trailingVisualId,
}}
>
<LiBox
ref={!buttonSemanticsFeatureFlag || listSemantics ? forwardedRef : null}
Expand Down
3 changes: 2 additions & 1 deletion packages/react/src/ActionList/Visuals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,10 @@ export const LeadingVisual: React.FC<React.PropsWithChildren<VisualProps>> = ({s

export type ActionListTrailingVisualProps = VisualProps
export const TrailingVisual: React.FC<React.PropsWithChildren<VisualProps>> = ({sx = {}, ...props}) => {
const {variant, disabled, inactive} = React.useContext(ItemContext)
const {variant, disabled, inactive, trailingVisualId} = React.useContext(ItemContext)
return (
<Box
id={trailingVisualId}
as="span"
sx={merge(
{
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/ActionList/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ type MenuItemProps = {
export type ItemContext = Pick<ActionListItemProps, 'variant' | 'disabled'> & {
inlineDescriptionId?: string
blockDescriptionId?: string
trailingVisualId?: string
inactive?: boolean
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1274,7 +1274,7 @@ exports[`NavList.Item with NavList.SubNav does not have active styles if SubNav
<button
aria-controls=":r27:"
aria-expanded="true"
aria-labelledby=":r26:--label "
aria-labelledby=":r26:--label :r26:--trailing-visual"
class="c3 c4"
id=":r26:"
tabindex="0"
Expand All @@ -1294,6 +1294,7 @@ exports[`NavList.Item with NavList.SubNav does not have active styles if SubNav
</span>
<span
class="c1 c8"
id=":r26:--trailing-visual"
>
<svg
aria-hidden="true"
Expand Down Expand Up @@ -1773,7 +1774,7 @@ exports[`NavList.Item with NavList.SubNav has active styles if SubNav contains t
<button
aria-controls=":r21:"
aria-expanded="false"
aria-labelledby=":r20:--label "
aria-labelledby=":r20:--label :r20:--trailing-visual"
class="c3 c4"
id=":r20:"
tabindex="0"
Expand All @@ -1793,6 +1794,7 @@ exports[`NavList.Item with NavList.SubNav has active styles if SubNav contains t
</span>
<span
class="c1 c8"
id=":r20:--trailing-visual"
>
<svg
aria-hidden="true"
Expand Down
Loading