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

[TrapFocus] Add documentation #22062

Merged
merged 6 commits into from
Aug 8, 2020
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
4 changes: 4 additions & 0 deletions docs/pages/api-docs/unstable-trap-focus.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,7 @@ Utility component that locks focus inside the component.
The component cannot hold a ref.


## Demos

- [Trap Focus](/components/trap-focus/)

20 changes: 20 additions & 0 deletions docs/pages/components/trap-focus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs';
import { prepareMarkdown } from 'docs/src/modules/utils/parseMarkdown';

const pageFilename = 'components/trap-focus';
const requireDemo = require.context('docs/src/pages/components/trap-focus', false, /\.(js|tsx)$/);
const requireRaw = require.context(
'!raw-loader!../../src/pages/components/trap-focus',
false,
/\.(js|md|tsx)$/,
);

export default function Page({ demos, docs }) {
return <MarkdownDocs demos={demos} docs={docs} requireDemo={requireDemo} />;
}

Page.getInitialProps = () => {
const { demos, docs } = prepareMarkdown({ pageFilename, requireRaw });
return { demos, docs };
};
1 change: 1 addition & 0 deletions docs/src/pages.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ const pages = [
{ pathname: '/components/speed-dial' },
{ pathname: '/components/timeline' },
{ pathname: '/components/toggle-button' },
{ pathname: '/components/trap-focus' },
{ pathname: '/components/tree-view' },
],
},
Expand Down
32 changes: 32 additions & 0 deletions docs/src/pages/components/trap-focus/BasicTrapFocus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as React from 'react';
import TrapFocus from '@material-ui/core/Unstable_TrapFocus';

export default function BasicTrapFocus() {
const [open, setOpen] = React.useState(false);
return (
<div>
<button type="button" onClick={() => setOpen(true)}>
Open
</button>
<br />
{open && (
<TrapFocus open isEnabled={() => true} getDoc={() => document}>
<div tabIndex={-1}>
<h3>Quick form</h3>
<label>
First name: <input type="text" />
</label>
<br />
<label>
Last name: <input type="text" />
</label>
<br />
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</div>
</TrapFocus>
)}
</div>
);
}
32 changes: 32 additions & 0 deletions docs/src/pages/components/trap-focus/BasicTrapFocus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as React from 'react';
import TrapFocus from '@material-ui/core/Unstable_TrapFocus';

export default function BasicTrapFocus() {
const [open, setOpen] = React.useState(false);
return (
<div>
<button type="button" onClick={() => setOpen(true)}>
Open
</button>
<br />
{open && (
<TrapFocus open isEnabled={() => true} getDoc={() => document}>
<div tabIndex={-1}>
<h3>Quick form</h3>
<label>
First name: <input type="text" />
</label>
<br />
<label>
Last name: <input type="text" />
</label>
<br />
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</div>
</TrapFocus>
)}
</div>
);
}
37 changes: 37 additions & 0 deletions docs/src/pages/components/trap-focus/DisableEnforceFocus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as React from 'react';
import TrapFocus from '@material-ui/core/Unstable_TrapFocus';

export default function DisableEnforceFocus() {
const [open, setOpen] = React.useState(false);
return (
<div>
<button type="button" onClick={() => setOpen(true)}>
Open
</button>
<br />
{open && (
<TrapFocus
disableEnforceFocus
open
isEnabled={() => true}
getDoc={() => document}
>
<div tabIndex={-1}>
<h3>Quick form</h3>
<label>
First name: <input type="text" />
</label>
<br />
<label>
Last name: <input type="text" />
</label>
<br />
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</div>
</TrapFocus>
)}
</div>
);
}
37 changes: 37 additions & 0 deletions docs/src/pages/components/trap-focus/DisableEnforceFocus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as React from 'react';
import TrapFocus from '@material-ui/core/Unstable_TrapFocus';

export default function DisableEnforceFocus() {
const [open, setOpen] = React.useState(false);
return (
<div>
<button type="button" onClick={() => setOpen(true)}>
Open
</button>
<br />
{open && (
<TrapFocus
disableEnforceFocus
open
isEnabled={() => true}
getDoc={() => document}
>
<div tabIndex={-1}>
<h3>Quick form</h3>
<label>
First name: <input type="text" />
</label>
<br />
<label>
Last name: <input type="text" />
</label>
<br />
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</div>
</TrapFocus>
)}
</div>
);
}
37 changes: 37 additions & 0 deletions docs/src/pages/components/trap-focus/LazyTrapFocus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as React from 'react';
import TrapFocus from '@material-ui/core/Unstable_TrapFocus';

export default function LazyTrapFocus() {
const [open, setOpen] = React.useState(false);
return (
<div>
<button type="button" onClick={() => setOpen(true)}>
Open
</button>
<br />
{open && (
<TrapFocus
open
isEnabled={() => true}
getDoc={() => document}
disableAutoFocus
>
<div tabIndex={-1}>
<h3>Quick form</h3>
<label>
First name: <input type="text" />
</label>
<br />
<label>
Last name: <input type="text" />
</label>
<br />
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</div>
</TrapFocus>
)}
</div>
);
}
37 changes: 37 additions & 0 deletions docs/src/pages/components/trap-focus/LazyTrapFocus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as React from 'react';
import TrapFocus from '@material-ui/core/Unstable_TrapFocus';

export default function LazyTrapFocus() {
const [open, setOpen] = React.useState(false);
return (
<div>
<button type="button" onClick={() => setOpen(true)}>
Open
</button>
<br />
{open && (
<TrapFocus
open
isEnabled={() => true}
getDoc={() => document}
disableAutoFocus
>
<div tabIndex={-1}>
<h3>Quick form</h3>
<label>
First name: <input type="text" />
</label>
<br />
<label>
Last name: <input type="text" />
</label>
<br />
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</div>
</TrapFocus>
)}
</div>
);
}
39 changes: 39 additions & 0 deletions docs/src/pages/components/trap-focus/PortalTrapFocus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import Portal from '@material-ui/core/Portal';
import TrapFocus from '@material-ui/core/Unstable_TrapFocus';

export default function PortalTrapFocus() {
const [open, setOpen] = React.useState(false);
const [container, setContainer] = React.useState(null);

return (
<div>
<button type="button" onClick={() => setOpen(true)}>
Open
</button>
<br />
{open && (
<TrapFocus open isEnabled={() => true} getDoc={() => document}>
<div tabIndex={-1}>
<h3>Quick form</h3>
<label>
First name: <input type="text" />
</label>
<br />
<Portal container={container}>
<label>
Last name: <input type="text" />
</label>
<br />
</Portal>
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</div>
</TrapFocus>
)}

<div ref={setContainer} />
</div>
);
}
38 changes: 38 additions & 0 deletions docs/src/pages/components/trap-focus/PortalTrapFocus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react';
import Portal from '@material-ui/core/Portal';
import TrapFocus from '@material-ui/core/Unstable_TrapFocus';

export default function PortalTrapFocus() {
const [open, setOpen] = React.useState(false);
const [container, setContainer] = React.useState<HTMLElement | null>(null);

return (
<div>
<button type="button" onClick={() => setOpen(true)}>
Open
</button>
<br />
{open && (
<TrapFocus open isEnabled={() => true} getDoc={() => document}>
<div tabIndex={-1}>
<h3>Quick form</h3>
<label>
First name: <input type="text" />
</label>
<br />
<Portal container={container}>
<label>
Last name: <input type="text" />
</label>
<br />
</Portal>
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</div>
</TrapFocus>
)}
<div ref={setContainer} />
</div>
);
}
45 changes: 45 additions & 0 deletions docs/src/pages/components/trap-focus/trap-focus.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
title: Trap Focus React component
components: Unstable_TrapFocus
---

# Trap Focus

<p class="description">Trap focus within a DOM node.</p>

> ⚠️ The component is experimental and unstable.

`TrapFocus` is a component that manages focus for its descendants.
This is useful when implementing overlays such as modal dialogs, which should not allow focus to escape while open.

When `open={true}` the trap is enabled, and pressing <kbd>Tab</kbd> or <kbd>Shift</kbd>+<kbd>Tab</kbd> will rotate focus within the inner focusable elements of the component.

- 📦 [1.5 kB gzipped](https://material-ui.com/size-snapshot).
- ⚛️ Support portals

## Example

{{"demo": "pages/components/trap-focus/BasicTrapFocus.js"}}

## Disable enforce focus

Clicks within the focus trap behave normally; but clicks outside the focus trap are blocked.

You can disable this behavior with the `disableEnforceFocus` prop.

{{"demo": "pages/components/trap-focus/DisableEnforceFocus.js"}}

## Lazy activation

By default, the component moves the focus to its descendants as soon as it opens: `open={true}`.

You can disable this behavior and make it lazy with the `disableAutoFocus` prop.
eps1lon marked this conversation as resolved.
Show resolved Hide resolved
When auto focus is disabled, as in the demo below, the component only traps the focus once it gets focused.

{{"demo": "pages/components/trap-focus/LazyTrapFocus.js"}}

## Portal

The following demo uses the [`Portal`](/components/portal/) component to render a subset of the trap focus children into a new "subtree" outside of the current DOM hierarchy, so that they no longer form part of the focus loop.

{{"demo": "pages/components/trap-focus/PortalTrapFocus.js"}}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ export interface TrapFocusProps {

/**
* Utility component that locks focus inside the component.
* Demos:
*
* - [Trap Focus](https://material-ui.com/components/trap-focus/)
*
* API:
*
* - [Unstable_TrapFocus API](https://material-ui.com/api/unstable-trap-focus/)
Expand Down