-
Notifications
You must be signed in to change notification settings - Fork 138
feat: accessibility improvements #363
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
base: master
Are you sure you want to change the base?
Changes from 5 commits
3c61fff
9f789a2
f8676e7
089346c
af2984e
55bc778
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
import classNames from 'classnames'; | ||
import CSSMotion from 'rc-motion'; | ||
import KeyCode from '@rc-component/util/lib/KeyCode'; | ||
import type { PropsWithChildren } from 'react'; | ||
import React from 'react'; | ||
import type { CollapsePanelProps } from './interface'; | ||
import PanelContent from './PanelContent'; | ||
|
@@ -25,6 +26,8 @@ const CollapsePanel = React.forwardRef<HTMLDivElement, CollapsePanelProps>((prop | |
openMotion, | ||
destroyInactivePanel, | ||
children, | ||
headingLevel, | ||
id, | ||
...resetProps | ||
} = props; | ||
|
||
|
@@ -85,20 +88,38 @@ const CollapsePanel = React.forwardRef<HTMLDivElement, CollapsePanelProps>((prop | |
...(['header', 'icon'].includes(collapsible) ? {} : collapsibleProps), | ||
}; | ||
|
||
const HeaderWrapper = ({ children: headerWrapperChildren }: PropsWithChildren) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
https://github.com/react-component/collapse/pull/363/files#r2092418393 |
||
if (!headingLevel) { | ||
return <>{headerWrapperChildren}</>; | ||
} else { | ||
return ( | ||
<div className={`${prefixCls}-header-wrapper`} role="heading" aria-level={headingLevel}> | ||
{headerWrapperChildren} | ||
</div> | ||
); | ||
} | ||
}; | ||
|
||
// ======================== Render ======================== | ||
return ( | ||
<div {...resetProps} ref={ref} className={collapsePanelClassNames}> | ||
<div {...headerProps}> | ||
{showArrow && iconNode} | ||
<span | ||
className={classNames(`${prefixCls}-title`, customizeClassNames?.title)} | ||
style={styles?.title} | ||
{...(collapsible === 'header' ? collapsibleProps : {})} | ||
<div {...resetProps} ref={ref} className={collapsePanelClassNames} id={id}> | ||
<HeaderWrapper> | ||
<div | ||
{...headerProps} | ||
id={id ? `${id}__header` : undefined} | ||
aria-controls={id ? `${id}__content` : undefined} | ||
> | ||
{header} | ||
</span> | ||
{ifExtraExist && <div className={`${prefixCls}-extra`}>{extra}</div>} | ||
</div> | ||
{showArrow && iconNode} | ||
<span | ||
className={classNames(`${prefixCls}-title`, customizeClassNames?.title)} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. replace this with HeadingElement instead of span directly. It's no need to have additional HeaderWrapper. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can change HeaderWrapper, but replacing the span would not satisfy the a11y standards for collapse / accordion components. The heading element should wrap the header button, which is where HeaderWrapper is in this PR. Would you prefer it to be a div that is always present around the button, instead of conditionally rendered, but it only would have the heading role and aria-level when the prop is defined? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK. So you can add on the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update - the rc-collapse-header element gets the button role, so to satisfy the a11y standards for the header, I changed to a div element that always wraps rc-collapse-header and will conditionally have the heading role and aria-level props set. |
||
style={styles?.title} | ||
{...(collapsible === 'header' ? collapsibleProps : {})} | ||
> | ||
{header} | ||
</span> | ||
{ifExtraExist && <div className={`${prefixCls}-extra`}>{extra}</div>} | ||
</div> | ||
</HeaderWrapper> | ||
<CSSMotion | ||
visible={isActive} | ||
leavedClassName={`${prefixCls}-panel-hidden`} | ||
|
@@ -110,6 +131,8 @@ const CollapsePanel = React.forwardRef<HTMLDivElement, CollapsePanelProps>((prop | |
return ( | ||
<PanelContent | ||
ref={motionRef} | ||
id={id ? `${id}__content` : undefined} | ||
aria-labelledby={id ? `${id}__header` : undefined} | ||
prefixCls={prefixCls} | ||
className={motionClassName} | ||
classNames={customizeClassNames} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,14 @@ import CollapsePanel from '../Panel'; | |
|
||
type Props = Pick< | ||
CollapsePanelProps, | ||
'prefixCls' | 'onItemClick' | 'openMotion' | 'expandIcon' | 'classNames' | 'styles' | ||
| 'prefixCls' | ||
| 'onItemClick' | ||
| 'openMotion' | ||
| 'expandIcon' | ||
| 'classNames' | ||
| 'styles' | ||
| 'headingLevel' | ||
| 'id' | ||
> & | ||
Pick<CollapseProps, 'accordion' | 'collapsible' | 'destroyInactivePanel'> & { | ||
activeKey: React.Key[]; | ||
|
@@ -23,6 +30,8 @@ const convertItemsToNodes = (items: ItemType[], props: Props) => { | |
expandIcon, | ||
classNames: collapseClassNames, | ||
styles, | ||
headingLevel, | ||
id, | ||
} = props; | ||
|
||
return items.map((item, index) => { | ||
|
@@ -71,6 +80,8 @@ const convertItemsToNodes = (items: ItemType[], props: Props) => { | |
collapsible={mergeCollapsible} | ||
onItemClick={handleItemClick} | ||
destroyInactivePanel={mergeDestroyInactivePanel} | ||
headingLevel={headingLevel} | ||
id={id ? `${id}__item-${index}` : undefined} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can use |
||
> | ||
{children} | ||
</CollapsePanel> | ||
|
@@ -99,6 +110,8 @@ const getNewChild = ( | |
expandIcon, | ||
classNames: collapseClassNames, | ||
styles, | ||
headingLevel, | ||
id, | ||
} = props; | ||
|
||
const key = child.key || String(index); | ||
|
@@ -142,6 +155,8 @@ const getNewChild = ( | |
onItemClick: handleItemClick, | ||
expandIcon, | ||
collapsible: mergeCollapsible, | ||
headingLevel, | ||
id: id ? `${id}__item-${index}` : undefined, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use |
||
}; | ||
|
||
// https://github.com/ant-design/ant-design/issues/20479 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not
id
butparentId