diff --git a/docs/src/pages/components/expansion-panels/ActionsInExpansionPanelSummary.js b/docs/src/pages/components/expansion-panels/ActionsInExpansionPanelSummary.js
new file mode 100644
index 00000000000000..821f8b8c126287
--- /dev/null
+++ b/docs/src/pages/components/expansion-panels/ActionsInExpansionPanelSummary.js
@@ -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 (
+
+
+ }
+ aria-label="Expand"
+ aria-controls="additional-actions1-content"
+ id="additional-actions1-header"
+ >
+ event.stopPropagation()}
+ onFocus={event => event.stopPropagation()}
+ control={}
+ label="I acknowledge that I should stop the click event propagation"
+ />
+
+
+
+ The click event of the nested action will propagate up and expand the panel unless you
+ explicitly stop it.
+
+
+
+
+ }
+ aria-label="Expand"
+ aria-controls="additional-actions2-content"
+ id="additional-actions2-header"
+ >
+ event.stopPropagation()}
+ onFocus={event => event.stopPropagation()}
+ control={}
+ label="I acknowledge that I should stop the focus event propagation"
+ />
+
+
+
+ The focus event of the nested action will propagate up and also focus the expansion
+ panel unless you explicitly stop it.
+
+
+
+
+ }
+ aria-label="Expand"
+ aria-controls="additional-actions3-content"
+ id="additional-actions3-header"
+ >
+ event.stopPropagation()}
+ onFocus={event => event.stopPropagation()}
+ control={}
+ label="I acknowledge that I should provide an aria-label on each action that I add"
+ />
+
+
+
+ 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.
+
+
+
+
+ );
+}
diff --git a/docs/src/pages/components/expansion-panels/ActionsInExpansionPanelSummary.tsx b/docs/src/pages/components/expansion-panels/ActionsInExpansionPanelSummary.tsx
new file mode 100644
index 00000000000000..821f8b8c126287
--- /dev/null
+++ b/docs/src/pages/components/expansion-panels/ActionsInExpansionPanelSummary.tsx
@@ -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 (
+
+
+ }
+ aria-label="Expand"
+ aria-controls="additional-actions1-content"
+ id="additional-actions1-header"
+ >
+ event.stopPropagation()}
+ onFocus={event => event.stopPropagation()}
+ control={}
+ label="I acknowledge that I should stop the click event propagation"
+ />
+
+
+
+ The click event of the nested action will propagate up and expand the panel unless you
+ explicitly stop it.
+
+
+
+
+ }
+ aria-label="Expand"
+ aria-controls="additional-actions2-content"
+ id="additional-actions2-header"
+ >
+ event.stopPropagation()}
+ onFocus={event => event.stopPropagation()}
+ control={}
+ label="I acknowledge that I should stop the focus event propagation"
+ />
+
+
+
+ The focus event of the nested action will propagate up and also focus the expansion
+ panel unless you explicitly stop it.
+
+
+
+
+ }
+ aria-label="Expand"
+ aria-controls="additional-actions3-content"
+ id="additional-actions3-header"
+ >
+ event.stopPropagation()}
+ onFocus={event => event.stopPropagation()}
+ control={}
+ label="I acknowledge that I should provide an aria-label on each action that I add"
+ />
+
+
+
+ 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.
+
+
+
+
+ );
+}
diff --git a/docs/src/pages/components/expansion-panels/DetailedExpansionPanel.js b/docs/src/pages/components/expansion-panels/DetailedExpansionPanel.js
index 4fe1071686225c..21e1709fa6f1c6 100644
--- a/docs/src/pages/components/expansion-panels/DetailedExpansionPanel.js
+++ b/docs/src/pages/components/expansion-panels/DetailedExpansionPanel.js
@@ -73,7 +73,7 @@ export default function DetailedExpansionPanel() {
Select your destination of choice
-
+
Learn more
diff --git a/docs/src/pages/components/expansion-panels/DetailedExpansionPanel.tsx b/docs/src/pages/components/expansion-panels/DetailedExpansionPanel.tsx
index 8f6b7ff870c67b..12d73dbdafd5f5 100644
--- a/docs/src/pages/components/expansion-panels/DetailedExpansionPanel.tsx
+++ b/docs/src/pages/components/expansion-panels/DetailedExpansionPanel.tsx
@@ -75,7 +75,7 @@ export default function DetailedExpansionPanel() {
Select your destination of choice
-
+
Learn more
diff --git a/docs/src/pages/components/expansion-panels/expansion-panels.md b/docs/src/pages/components/expansion-panels/expansion-panels.md
index f4446e19975a16..ca84c269dcbf4c 100644
--- a/docs/src/pages/components/expansion-panels/expansion-panels.md
+++ b/docs/src/pages/components/expansion-panels/expansion-panels.md
@@ -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.
diff --git a/packages/material-ui/src/ExpansionPanelSummary/ExpansionPanelSummary.js b/packages/material-ui/src/ExpansionPanelSummary/ExpansionPanelSummary.js
index 81d71a8ff81b4c..5d3227e2db020a 100644
--- a/packages/material-ui/src/ExpansionPanelSummary/ExpansionPanelSummary.js
+++ b/packages/material-ui/src/ExpansionPanelSummary/ExpansionPanelSummary.js
@@ -1,3 +1,4 @@
+/* eslint-disable jsx-a11y/aria-role */
import React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
@@ -128,13 +129,13 @@ const ExpansionPanelSummary = React.forwardRef(function ExpansionPanelSummary(pr
{children}
{expandIcon && (
diff --git a/packages/material-ui/src/ExpansionPanelSummary/ExpansionPanelSummary.test.js b/packages/material-ui/src/ExpansionPanelSummary/ExpansionPanelSummary.test.js
index 73c129ef216b3a..ce91479de99bad 100644
--- a/packages/material-ui/src/ExpansionPanelSummary/ExpansionPanelSummary.test.js
+++ b/packages/material-ui/src/ExpansionPanelSummary/ExpansionPanelSummary.test.js
@@ -38,25 +38,21 @@ describe('', () => {
expect(getByRole('button')).to.have.class(classes.disabled);
});
- it('when expanded adds the expanded class to any button regardless of a11y', () => {
- const { getAllByRole } = render();
-
- 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();
+
+ 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(Icon} />);
+ it('should render with an inaccessible expand icon and have the expandIcon class', () => {
+ const { container } = render(Icon} />);
- 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', () => {