-
Notifications
You must be signed in to change notification settings - Fork 77
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
fix: list selection behavior + accessibility #1167
Conversation
associate header as list label
Deploy preview for fundamental-react ready! Built with commit 0c28fd9 |
src/List/List.js
Outdated
{listHeader && React.cloneElement(listHeader, { id: `${listId}-label` })} | ||
<ul | ||
{...props} | ||
{...(selectable ? { 'role': 'listbox' } : null)} |
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.
Slightly easier to read syntax:
role={selectable ? 'listbox' : undefined}
src/List/List.js
Outdated
{...props} | ||
{...(selectable ? { 'role': 'listbox' } : null)} | ||
aria-labelledby={listHeader ? `${listId}-label` : null} | ||
className={ListClasses} |
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.
quick unrelated change ListClasses
-> listClasses
src/List/List.js
Outdated
id={`${listId}-list`} | ||
ref={ref}> | ||
{ React.Children.map(children, child => { | ||
if (!(isHeader(child) || isFooter(child)) ) { |
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.
probably a nitpick
if (!(isHeader(child) || isFooter(child)) ) {
vs
if (!isHeader(child) && !isFooter(child)) {
But it brings up a bigger issue to me, we aren't supporting custom components or fragments. We should be able to consume this code and add the right props to the right children
const MyOtherItems = () => (
<React.Fragment>
<List.Item>
<List.Text>List Item 2</List.Text>
</List.Item>
<List.Item>
<List.Text>List Item 3</List.Text>
</List.Item>
<List.Item>
<List.Text>List Item 4</List.Text>
</List.Item>
</React.Fragment>
);
// ....
const MyListHeader = () => <List.Header>List Header</List.Header>
// ...
<List>
<MyListHeader />
<List.Item>
<List.Text>List Item 1</List.Text>
</List.Item>
<MyOtherItems />
<List.Footer>List Footer</List.Footer>
</List>
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.
Thanks for pointing this out. I removed the children scanning and made the header and footer as List props.
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.
That's an interesting idea to get around the problem. I think we might want it to look more like this though
<List
footer='My footer'
header='My header'>
// ...
and the List component would render them like
return (
<>
{header && <List.Header id={`${listId}-label`}>{header}</List.Header>}
// ...
{footer && <List.Footer>{footer}</List.Footer>}
</>
footer: PropTypes.node,
header: PropTypes.node,
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 will mean that we cannot get fancy with the header and footer like here, right?
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.
I guess it would look like
footer = {<React.Fragment><List.Text><b>Total</b></List.Text><List.Text secondary>7</List.Text></React.Fragment>}
instead of
footer={
<List.Footer>
<List.Text><b>Total</b></List.Text>
<List.Text secondary>7</List.Text>
</List.Footer>
}
src/List/List.js
Outdated
/** Set to **true** if any list item has a byline. */ | ||
hasByline: PropTypes.bool, | ||
/** The list header as a String or a React component.*/ | ||
header: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), |
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.
React component
PropTypes.object
It's more accurate to say React node and PropTypes.node
@@ -13,9 +13,9 @@ const ListFooter = ({ | |||
); | |||
|
|||
return ( | |||
<li {...props} className={ListItemClasses}> | |||
<span {...props} className={ListItemClasses}> |
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 seems right to change the footer to a span, but do we need to stay in line with fundamental-styles here?
I've looked at a few of their examples and they all still show the footer as a li
, like here: https://github.com/SAP/fundamental-styles/blob/master/stories/list/standard/standard-list.stories.js#L301
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.
I guess this is part of
deviates from fundamental-styles markup for accessibility reasons
from your description, but is that OK to do? Do we document our deviations?
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.
Trying to get Got this change in fundamental-styles: SAP/fundamental-styles#1397
We can either jump the gun and get this change in fd-react or wait for the fd-styles change and subsequent fd-styles upgrade in fd-react.
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.
I'm for jumping the gun, as we will eventually be up to spec when fd-styles is upgraded :)
Description
In this change, we
selected
property forList.Selection
to allow setting the checked state of the checkbox. This property will be internally set by the parentList.Item
component based on theList.Item.selected
property.selectable
property toList
tofd-list--selection
class to<ul>
<ul>
role='listbox'List.Header
andList.Footer
from the list structure, they should be passed through the newheader
andfooter
List props.List.Header
renders<h2-6>
depending onList.headerLevel
List.Footer
renders<span>
id
property toList
to associateList.Header
as labelcheckBoxAriaLabel
toList.Selection
for accessibilityheaderClassName
andfooterClassName
props to allow custom classesScreen cap
Before
After
Know issues
deviates from fundamental-styles markup for accessibility reasonsfixes #1164 #970