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

[docs] Add demo for actions in ExpansionPanelSummary #17969

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import ExpansionPanel from '@material-ui/core/ExpansionPanel';
import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary';
import ExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails';
import Checkbox from '@material-ui/core/Checkbox';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import Typography from '@material-ui/core/Typography';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';

const useStyles = makeStyles({
root: {
width: '100%',
},
});

export default function ActionsInExpansionPanelSummary() {
const classes = useStyles();

return (
<div className={classes.root}>
<ExpansionPanel>
<ExpansionPanelSummary
expandIcon={<ExpandMoreIcon />}
aria-label="Expand"
aria-controls="additional-actions1-content"
id="additional-actions1-header"
>
<FormControlLabel
aria-label="Acknowledge"
onClick={event => event.stopPropagation()}
onFocus={event => event.stopPropagation()}
control={<Checkbox />}
label="I acknowledge that I should stop the click event propagation"
/>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<Typography color="textSecondary">
The click event of the nested action will propagate up and expand the panel unless you
explicitly stop it.
</Typography>
</ExpansionPanelDetails>
</ExpansionPanel>
<ExpansionPanel>
<ExpansionPanelSummary
expandIcon={<ExpandMoreIcon />}
aria-label="Expand"
aria-controls="additional-actions2-content"
id="additional-actions2-header"
>
<FormControlLabel
aria-label="Acknowledge"
onClick={event => event.stopPropagation()}
onFocus={event => event.stopPropagation()}
control={<Checkbox />}
label="I acknowledge that I should stop the focus event propagation"
/>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<Typography color="textSecondary">
The focus event of the nested action will propagate up and also focus the expansion
panel unless you explicitly stop it.
</Typography>
</ExpansionPanelDetails>
</ExpansionPanel>
<ExpansionPanel>
<ExpansionPanelSummary
expandIcon={<ExpandMoreIcon />}
aria-label="Expand"
aria-controls="additional-actions3-content"
id="additional-actions3-header"
>
<FormControlLabel
aria-label="Acknowledge"
onClick={event => event.stopPropagation()}
onFocus={event => event.stopPropagation()}
control={<Checkbox />}
label="I acknowledge that I should provide an aria-label on each action that I add"
/>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<Typography color="textSecondary">
If you forget to put an aria-label on the nested action, the label of the action will
also be included in the label of the parent button that controls the panel expansion.
</Typography>
</ExpansionPanelDetails>
</ExpansionPanel>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import ExpansionPanel from '@material-ui/core/ExpansionPanel';
import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary';
import ExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails';
import Checkbox from '@material-ui/core/Checkbox';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import Typography from '@material-ui/core/Typography';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';

const useStyles = makeStyles({
root: {
width: '100%',
},
});

export default function ActionsInExpansionPanelSummary() {
const classes = useStyles();

return (
<div className={classes.root}>
<ExpansionPanel>
<ExpansionPanelSummary
expandIcon={<ExpandMoreIcon />}
aria-label="Expand"
aria-controls="additional-actions1-content"
id="additional-actions1-header"
>
<FormControlLabel
aria-label="Acknowledge"
onClick={event => event.stopPropagation()}
onFocus={event => event.stopPropagation()}
control={<Checkbox />}
label="I acknowledge that I should stop the click event propagation"
/>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<Typography color="textSecondary">
The click event of the nested action will propagate up and expand the panel unless you
explicitly stop it.
</Typography>
</ExpansionPanelDetails>
</ExpansionPanel>
<ExpansionPanel>
<ExpansionPanelSummary
expandIcon={<ExpandMoreIcon />}
aria-label="Expand"
aria-controls="additional-actions2-content"
id="additional-actions2-header"
>
<FormControlLabel
aria-label="Acknowledge"
onClick={event => event.stopPropagation()}
onFocus={event => event.stopPropagation()}
control={<Checkbox />}
label="I acknowledge that I should stop the focus event propagation"
/>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<Typography color="textSecondary">
The focus event of the nested action will propagate up and also focus the expansion
panel unless you explicitly stop it.
</Typography>
</ExpansionPanelDetails>
</ExpansionPanel>
<ExpansionPanel>
<ExpansionPanelSummary
expandIcon={<ExpandMoreIcon />}
aria-label="Expand"
aria-controls="additional-actions3-content"
id="additional-actions3-header"
>
<FormControlLabel
aria-label="Acknowledge"
onClick={event => event.stopPropagation()}
onFocus={event => event.stopPropagation()}
control={<Checkbox />}
label="I acknowledge that I should provide an aria-label on each action that I add"
/>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<Typography color="textSecondary">
If you forget to put an aria-label on the nested action, the label of the action will
also be included in the label of the parent button that controls the panel expansion.
</Typography>
</ExpansionPanelDetails>
</ExpansionPanel>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export default function DetailedExpansionPanel() {
<Typography variant="caption">
Select your destination of choice
<br />
<a href="#sub-labels-and-columns" className={classes.link}>
<a href="#secondary-heading-and-columns" className={classes.link}>
Learn more
</a>
</Typography>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export default function DetailedExpansionPanel() {
<Typography variant="caption">
Select your destination of choice
<br />
<a href="#sub-labels-and-columns" className={classes.link}>
<a href="#secondary-heading-and-columns" className={classes.link}>
Learn more
</a>
</Typography>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ Here is an example of customizing the component. You can learn more about this i

{{"demo": "pages/components/expansion-panels/CustomizedExpansionPanels.js"}}

## Additional actions

In order to put an action such as a `Checkbox` or a button inside of the `ExpansionPanelSummary`, you need to stop the propagation of the focus and click events to prevent the panel from
expanding/collapsing when using the action.
You should also provide an `aria-label` for the action, otherwise the label of the nested action will be included in
the label of the parent button that controls the panel expansion.

{{"demo": "pages/components/expansion-panels/ActionsInExpansionPanelSummary.js"}}

## Performance

The content of ExpansionPanels is mounted by default even if the panel is not expanded.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable jsx-a11y/aria-role */
import React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
Expand Down Expand Up @@ -128,13 +129,13 @@ const ExpansionPanelSummary = React.forwardRef(function ExpansionPanelSummary(pr
<div className={clsx(classes.content, { [classes.expanded]: expanded })}>{children}</div>
{expandIcon && (
<IconButton
disabled={disabled}
className={clsx(classes.expandIcon, {
[classes.expanded]: expanded,
})}
edge="end"
component="div"
tabIndex={-1}
tabIndex={null}
Copy link
Member

@oliviertassinari oliviertassinari Oct 21, 2019

Choose a reason for hiding this comment

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

Fix:

Capture d’écran 2019-10-21 à 23 14 36
https://validator.w3.org/

Prior to this change, if you click the icon, the space key action didn't trigger the expansion panel.

role={null}
aria-hidden
{...IconButtonProps}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,25 +38,21 @@ describe('<ExpansionPanelSummary />', () => {
expect(getByRole('button')).to.have.class(classes.disabled);
});

it('when expanded adds the expanded class to any button regardless of a11y', () => {
const { getAllByRole } = render(<ExpansionPanelSummary expanded expandIcon="expand" />);

const buttons = getAllByRole('button', { hidden: true });
expect(buttons).to.have.length(2);
expect(buttons[0]).to.have.class(classes.expanded);
expect(buttons[0]).to.have.attribute('aria-expanded', 'true');
expect(buttons[0]).not.to.be.inaccessible;
expect(buttons[1]).to.have.class(classes.expanded);
expect(buttons[1]).to.be.inaccessible;
it('when expanded adds the expanded class to the button and expandIcon', () => {
const { container, getByRole } = render(<ExpansionPanelSummary expanded expandIcon="expand" />);

const button = getByRole('button');
expect(button).to.have.class(classes.expanded);
expect(button).to.have.attribute('aria-expanded', 'true');
expect(container.querySelector(`.${classes.expandIcon}`)).to.have.class(classes.expanded);
});

it('should render with the expand icon and have the expandIcon class', () => {
const { getAllByRole } = render(<ExpansionPanelSummary expandIcon={<div>Icon</div>} />);
it('should render with an inaccessible expand icon and have the expandIcon class', () => {
const { container } = render(<ExpansionPanelSummary expandIcon={<div>Icon</div>} />);

const expandButton = getAllByRole('button', { hidden: true })[1];
expect(expandButton).to.have.class(classes.expandIcon);
expect(expandButton).to.have.text('Icon');
expect(expandButton).to.be.inaccessible;
const expandIcon = container.querySelector(`.${classes.expandIcon}`);
expect(expandIcon).to.have.text('Icon');
expect(expandIcon).to.be.inaccessible;
});

it('focusing adds the `focused` class if focused visible', () => {
Expand Down