diff --git a/docs/data/material/components/snackbars/snackbars.md b/docs/data/material/components/snackbars/snackbars.md
index 2bda8ee964613a..be4ae038f3d337 100644
--- a/docs/data/material/components/snackbars/snackbars.md
+++ b/docs/data/material/components/snackbars/snackbars.md
@@ -122,6 +122,10 @@ Note that notistack prevents Snackbars from being [closed by pressing F6. This allows keyboard users to access the Snackbar and its interactive elements without having to tab through the entire page.
+
The user should be able to dismiss Snackbars by pressing Escape. If there are multiple instances appearing at the same time and you want Escape to dismiss only the oldest one that's currently open, call `event.preventDefault` in the `onClose` prop.
```jsx
diff --git a/packages/mui-material/src/Snackbar/Snackbar.js b/packages/mui-material/src/Snackbar/Snackbar.js
index 4d015d43f665aa..c8832b5856f1d8 100644
--- a/packages/mui-material/src/Snackbar/Snackbar.js
+++ b/packages/mui-material/src/Snackbar/Snackbar.js
@@ -139,8 +139,34 @@ const Snackbar = React.forwardRef(function Snackbar(inProps, ref) {
const { getRootProps, onClickAway } = useSnackbar(ownerState);
+ const snackbarRef = React.useRef(null);
+
const [exited, setExited] = React.useState(true);
+ React.useEffect(() => {
+ if (!open) {
+ return undefined;
+ }
+
+ /**
+ * @param {KeyboardEvent} nativeEvent
+ */
+ function handleKeyDown(nativeEvent) {
+ if (!nativeEvent.defaultPrevented) {
+ if (nativeEvent.key === 'F6' && snackbarRef.current) {
+ nativeEvent.preventDefault();
+ snackbarRef.current.focus();
+ }
+ }
+ }
+
+ document.addEventListener('keydown', handleKeyDown);
+
+ return () => {
+ document.removeEventListener('keydown', handleKeyDown);
+ };
+ }, [open]);
+
const handleExited = (node) => {
setExited(true);
@@ -174,7 +200,12 @@ const Snackbar = React.forwardRef(function Snackbar(inProps, ref) {
ref,
className: [classes.root, className],
elementType: SnackbarRoot,
- getSlotProps: getRootProps,
+ getSlotProps: (handlers) => ({
+ ...getRootProps(handlers),
+ ref: snackbarRef,
+ tabIndex: 0,
+ role: 'status',
+ }),
externalForwardedProps: {
...externalForwardedProps,
...other,
diff --git a/packages/mui-material/src/Snackbar/Snackbar.test.js b/packages/mui-material/src/Snackbar/Snackbar.test.js
index 0789ddadf86537..0fb0458eef4f19 100644
--- a/packages/mui-material/src/Snackbar/Snackbar.test.js
+++ b/packages/mui-material/src/Snackbar/Snackbar.test.js
@@ -635,4 +635,59 @@ describe('', () => {
expect(handleClose.callCount).to.equal(0);
});
+ describe('F6 keyboard shortcut', () => {
+ it('should focus Snackbar when F6 is pressed', () => {
+ const { container } = render();
+
+ const snackbar = container.querySelector('[role="status"]');
+ expect(snackbar).not.to.equal(null);
+ expect(snackbar).not.to.equal(document.activeElement);
+
+ fireEvent.keyDown(document.body, { key: 'F6' });
+
+ expect(snackbar).to.equal(document.activeElement);
+ });
+
+ it('should not focus when Snackbar is closed', () => {
+ render();
+
+ const snackbar = document.querySelector('[role="status"]');
+ expect(snackbar).to.equal(null);
+
+ fireEvent.keyDown(document.body, { key: 'F6' });
+
+ expect(document.activeElement).to.equal(document.body);
+ });
+
+ it('should have role="status" for accessibility', () => {
+ const { container } = render();
+
+ const snackbar = container.querySelector('[role="status"]');
+ expect(snackbar).not.to.equal(null);
+ });
+
+ it('should have tabIndex="0" to be focusable', () => {
+ const { container } = render();
+
+ const snackbar = container.querySelector('[role="status"]');
+ expect(snackbar.getAttribute('tabindex')).to.equal('0');
+ });
+
+ it('should work with multiple Snackbars', () => {
+ const { container } = render(
+
+
+
+ ,
+ );
+
+ fireEvent.keyDown(document.body, { key: 'F6' });
+
+ const snackbars = container.querySelectorAll('[role="status"]');
+ expect(snackbars.length).to.equal(2);
+
+ const focusedSnackbar = Array.from(snackbars).find((s) => s === document.activeElement);
+ expect(focusedSnackbar).not.to.equal(undefined);
+ });
+ });
});