Skip to content

Commit

Permalink
[TrapFocus] Add documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
oliviertassinari committed Aug 3, 2020
1 parent 7994e11 commit 4a42889
Show file tree
Hide file tree
Showing 13 changed files with 374 additions and 0 deletions.
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
26 changes: 26 additions & 0 deletions docs/src/pages/components/trap-focus/BasicTrapFocus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
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>
<input aria-label="First name" placeholder="First name" />
<input aria-label="Last name" placeholder="Last name" />
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</div>
</TrapFocus>
)}
</div>
);
}
26 changes: 26 additions & 0 deletions docs/src/pages/components/trap-focus/BasicTrapFocus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
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>
<input aria-label="First name" placeholder="First name" />
<input aria-label="Last name" placeholder="Last name" />
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</div>
</TrapFocus>
)}
</div>
);
}
31 changes: 31 additions & 0 deletions docs/src/pages/components/trap-focus/DisableEnforceFocus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
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>
<input aria-label="First name" placeholder="First name" />
<input aria-label="Last name" placeholder="Last name" />
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</div>
</TrapFocus>
)}
</div>
);
}
31 changes: 31 additions & 0 deletions docs/src/pages/components/trap-focus/DisableEnforceFocus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
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>
<input aria-label="First name" placeholder="First name" />
<input aria-label="Last name" placeholder="Last name" />
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</div>
</TrapFocus>
)}
</div>
);
}
31 changes: 31 additions & 0 deletions docs/src/pages/components/trap-focus/DisableRestoreFocus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import * as React from 'react';
import TrapFocus from '@material-ui/core/Unstable_TrapFocus';

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

export default function DisableRestoreFocus() {
const [open, setOpen] = React.useState(false);
return (
<div>
<button type="button" onClick={() => setOpen(true)}>
Open
</button>
<br />
{open && (
<TrapFocus
disableRestoreFocus
open
isEnabled={() => true}
getDoc={() => document}
>
<div tabIndex={-1}>
<h3>Quick form</h3>
<input aria-label="First name" placeholder="First name" />
<input aria-label="Last name" placeholder="Last name" />
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</div>
</TrapFocus>
)}
</div>
);
}
31 changes: 31 additions & 0 deletions docs/src/pages/components/trap-focus/LazyTrapFocus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
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>
<input aria-label="First name" placeholder="First name" />
<input aria-label="Last name" placeholder="Last name" />
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</div>
</TrapFocus>
)}
</div>
);
}
31 changes: 31 additions & 0 deletions docs/src/pages/components/trap-focus/LazyTrapFocus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
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>
<input aria-label="First name" placeholder="First name" />
<input aria-label="Last name" placeholder="Last name" />
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</div>
</TrapFocus>
)}
</div>
);
}
33 changes: 33 additions & 0 deletions docs/src/pages/components/trap-focus/PortalTrapFocus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
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>
<input aria-label="First name" placeholder="First name" />
<Portal container={container}>
<input aria-label="Last name" placeholder="Last name" />
</Portal>
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</div>
</TrapFocus>
)}

<div ref={setContainer} />
</div>
);
}
32 changes: 32 additions & 0 deletions docs/src/pages/components/trap-focus/PortalTrapFocus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
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>
<input aria-label="First name" placeholder="First name" />
<Portal container={container}>
<input aria-label="Last name" placeholder="Last name" />
</Portal>
<button type="button" onClick={() => setOpen(false)}>
Close
</button>
</div>
</TrapFocus>
)}
<div ref={setContainer} />
</div>
);
}
50 changes: 50 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,50 @@
---
title: Trap Focus React component
components: Unstable_TrapFocus
---

# Trap Focus

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

`TrapFocus` is a utility component that manage focus for its descendants.
This is useful when implementing overlays like modal dialogs, which should not allow focus to escape them while open.

When `open={true}` the trap enables, pressing <kbd>Tab</kbd> or <kbd>Shift+Tab</kbd> will circle 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 the behavior with the `disableEnforceFocus` prop.

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

## Disable restore focus

The component restores the focus back to the previously focused element when it deactivates, for example, back to a button which opened a dialog.

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

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

## Lazy activation

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

You can disale this behavior, and make it lazy, with the `disableAutoFocus` prop.

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

## Portal

The following demo uses [`Portal`](/components/portal/) to render a part of the trap focus into a new "subtree" outside of current DOM hierarchy.

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

0 comments on commit 4a42889

Please sign in to comment.