Followed By WAI-ARIA Authoring Practices 1.1
A dialog is a window overlaid on either the primary window or another dialog window. Windows under a modal dialog are inert. That is, users cannot interact with content outside an active dialog window. Inert content outside an active dialog is typically visually obscured or dimmed so it is difficult to discern, and in some implementations, attempts to interact with the inert content cause the dialog to close.
Like non-modal dialogs, modal dialogs contain their tab sequence. That is, Tab and Shift + Tab do not move focus outside the dialog. However, unlike most non-modal dialogs, modal dialogs do not provide means for moving keyboard focus outside the dialog window without closing the dialog.
In the following description, the term tabbable element refers to any element with a tabindex value of zero or greater. Note that values greater than 0 are strongly discouraged.
- When a dialog opens, focus moves to an element inside the dialog. See notes below regarding initial focus placement.
- Tab:
- Moves focus to the next tabbable element inside the dialog.
- If focus is on the last tabbable element inside the dialog, moves focus to the first tabbable element inside the dialog.
- Shift + Tab:
- Moves focus to the previous tabbable element inside the dialog.
- If focus is on the first tabbable element inside the dialog, moves focus to the last tabbable element inside the dialog.
- Escape: Closes the dialog.
1.
When a dialog opens, focus placement depends on the nature and size of the content
- In all circumstances, focus moves to an element contained in the dialog.
- Unless a condition where doing otherwise is advisable, focus is initially set on the first focusable element.
- If content is large enough that focusing the first interactive element could cause the beginning of content to scroll out of view, it is advisable to add
tabindex=-1
to a static element at the top of the dialog, such as the dialog title or first paragraph, and initially focus that element.- If a dialog contains the final step in a process that is not easily reversible, such as deleting data or completing a financial transaction, it may be advisable to set focus on the least destructive action, especially if undoing the action is difficult or impossible. The Alert Dialog Pattern is often employed in such circumstances.
- If a dialog is limited to interactions that either provide additional information or continue processing, it may be advisable to set focus to the element that is likely to be most frequently used, such as an
OK or Continue button
.
2:
When a dialog closes, focus returns to the element that invoked the dialog unless either:
- The invoking element no longer exists. Then, focus is set on another element that provides logical work flow.
- The work flow design includes the following conditions that can occasionally make focusing a different element a more logical choice:
1:
It is very unlikely users need to immediately re-invoke the dialog.
2:
The task completed in the dialog is directly related to a subsequent step in the work flow.
For example, a grid has an associated toolbar with a button for adding rows. the Add Rows
button opens a dialog that prompts for the number of rows. After the dialog closes, focus
is placed in the first cell of the first new row.
3:
It is strongly recommended that the tab sequence of all dialogs include a visible element
with role button that closes the dialog, such as a close icon or cancel button.
- The element that serves as the dialog container has a role of dialog.
- All elements required to operate the dialog are descendants of the element that has role dialog.
- The dialog container element has aria-modal set to true.
- `The dialog has either:`
- A value set for the aria-labelledby property that refers to a visible dialog title.
- A label specified by aria-label.
- Optionally, the aria-describedby property is set on the element with the dialog role to indicate which element or elements in the dialog contain content that describes the primary purpose or message of the dialog. Specifying descriptive elements enables screen readers to announce the description along with the dialog title and initially focused element when the dialog opens.
- Because marking a dialog modal by setting aria-modal to true can prevent users of some assistive technologies from perceiving content outside the dialog, users of those technologies will experience severe negative ramifications if a dialog is marked modal but does not behave as a modal for other users. So, mark a dialog modal only when both:
1: Application code prevents all users from interacting in any way with content outside of it.
2: Visual styling obscures the content outside of it.- The aria-modal property introduced by ARIA 1.1 replaces aria-hidden for informing assistive technologies that content outside a dialog is inert. However, in legacy dialog implementations where aria-hiddenis used to make content outside a dialog inert for assistive technology users, it is important that:
1: aria-hidden is set to true on each element containing a portion of the inert layer.
2: The dialog element is not a descendant of any element that has aria-hidden set to true.
Key | Function |
---|---|
Tab |
|
Shift + Tab |
|
Escape | Closes the dialog. |
Role | Attribute | Element | Usage |
---|---|---|---|
dialog | div | Identifies the element that serves as the dialog container. | |
aria-labelledby="IDREF" | div | Gives the dialog an accessible name by referring to the element that provides the dialog title. | |
aria-labelledby="IDREF" | div |
|
|
aria-modal="true" | div | Tells assistive technologies that the windows underneath the current dialog are not available for interaction (inert). |
Notes on aria-modal and aria-hidden
- The aria-modal property was introduced in ARIA 1.1. As a new property, screen reader users may experience varying degrees of support for it.
- Applying the aria-modal property to the dialog element replaces the technique of using aria-hidden on the background for informing assistive technologies that content outside a dialog is inert.
- In legacy dialog implementations where aria-hidden is used to make content outside a dialog inert for assistive technology users, it is important that:
- aria-hidden is set to true on each element containing a portion of the inert layer.
- The dialog element is not a descendant of any element that hasaria-hidden set to true.
index.html file
-------------
<!DOCTYPE html>
<html lang="en">
<body>
<div id="app-root"></div>
<div id="modal-root"></div>
</body>
</html>
App.js File
------------
import React, { Component } from 'react';
import Modal from "./Components/Modal/Modal";
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = { open: false}
}
openModal = () => {
this.setState({ open: true});
}
closeModal = () => {
this.setState({ open: false });
}
render() {
return (
<div className="App">
<header className="App-header">
Hello From Accessible React Modal
</header>
<section>
<button className="focusAfterClose" onClick={ this.openModal } >Awesome Modal</button>
</section>
<Modal
id="dialog1"
isOpen={ this.state.open }
onClose={this.closeModal}
label="Awesome Modal"
focusAfterClose="focusAfterClose"
>
<section>
<h4>This a awesome Modal </h4>
<p>This is a paragraph from awesome modal</p>
</section>
<button>Ok</button>
<button onClick={ this.openModal }>Process Next</button>
</Modal>
</div>
);
}
}
export default App;
index.js file
-----------
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('app-root')
);
CSS
/* Modal */
.hidden {
display: none;
}
[role="alertdialog"],
[role="dialog"] {
box-sizing: border-box;
padding: 15px;
border: 1px solid rgb(117, 116, 116);
background-color: #fff;
min-height: 100vh;
}
@media screen and (min-width: 640px) {
[role="alertdialog"],
[role="dialog"] {
position: absolute;
top: 4rem;
left: 50vw; /* move to the middle of the screen (assumes relative parent is the body/viewport) */
transform: translateX(
-50%
); /* move backwards 50% of this element's width */
min-width: calc(640px - (15px * 2)); /* == breakpoint - left+right margin */
min-height: auto;
box-shadow: 0 19px 38px rgba(0, 0, 0, 0.12), 0 15px 12px rgba(0, 0, 0, 0.22);
}
}
.dialog_label {
text-align: center;
}
.dialog_title {
display: inline-block;
padding: 0 5px;
}
.dialog_close_button {
float: right;
position: absolute;
top: 10px;
left: 92%;
height: 25px;
}
/* native <dialog> element uses the ::backdrop pseudo-element */
/* dialog::backdrop, */
.dialog-backdrop {
display: none;
position: fixed;
overflow-y: auto;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
@media screen and (min-width: 640px) {
.dialog-backdrop {
background: rgba(0, 0, 0, 0.3);
}
}
.dialog-backdrop.active {
display: block;
}
.no-scroll {
overflow-y: auto !important;
}
/* this is added to the body when a dialog is open */
.has-dialog {
overflow: hidden;
}
.focus_trap {
display: inline-block;
position: absolute;
border: none;
top: -20px;
background-color: white;
}
.focus_trap:focus {
border: none;
background-color: white;
display: inline-block;
position: absolute;
top: -20px;
}
*:focus {
outline-style: auto;
border-radius: 5px;
}
.modal_warning {
display: block;
text-align: center;
}
import React, { Component } from 'react';
import Modal from "./Components/Modal/Modal";
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = { open: false, id: null }
}
openModal = (dialogId) => {
this.setState({ open: true, id: dialogId });
}
closeModal = () => {
this.setState({ open: false });
}
render() {
return (
<div className="App">
<header className="App-header">
Hello From Accessible React Modal
</header>
<section>
<button className="focusAfterClose" onClick={ () => this.openModal("dialog1")} >Awesome Modal</button>
</section>
<Modal
id="dialog1"
isOpen={this.state.id === "dialog1" ? this.state.open : false}
onClose={this.closeModal}
label="Awesome Modal"
focusAfterClose="focusAfterClose"
>
<section>
<h4>This a awesome Modal </h4>
<p>This is a paragraph from awesome modal</p>
</section>
<button>Ok</button>
<button onClick={()=> this.openModal("dialog2")}>Process Next</button>
</Modal>
<Modal
id="dialog2"
isOpen={this.state.id === "dialog2" ? this.state.open : false}
onClose={this.closeModal}
label="Awesome Modal"
focusAfterClose="focusAfterClose"
>
<section>
<h4>This a awesome Modal </h4>
<p>This is a paragraph from awesome modal</p>
</section>
<button>Confirm</button>
</Modal>
</div>
);
}
}
export default App;
index.html file
-------------
<!DOCTYPE html>
<html lang="en">
<body>
<div id="app-root"></div>
<div id="modal-root"></div>
</body>
</html>
- Set your index.html file just like the above mention
<Modal
id="dialog1"
isOpen={ this.state.open }
onClose={this.closeModal}
label="Awesome Modal"
focusAfterClose="focusAfterClose"
>
</Modal>
id props
refers to the id of the modalisOpen props
props determine wheater the modal is open or close statelabel props
must have a label props which is the first focusable element inside the modal when the modal is openfocusAfterClose props
props is required, when modal close focus back to this elementclassName="focusAfterClose"
an element must have this className which will receive focus after the modal is close, typically the button element which trigger the modal
- initialize your state
this.state = { open: false, id: null }
// openModal function will receive an id @param
// and called with an id @param
openModal = (dialogId) => {
this.setState({ open: true, id: dialogId });
}
// function to be called like this
<button
className="focusAfterClose"
onClick={ () => this.openModal("dialog1")} >
Awesome Modal
</button>
//isOpen is set based on the condition
<Modal
id="dialog1"
isOpen={this.state.id === "dialog1" ? this.state.open : false}
onClose={this.closeModal}
label="Awesome Modal"
focusAfterClose="focusAfterClose"
>
</Modal>
modalClass
to style themodal
dialogLabelStyle
to style dialoglabel
elementtitleStyle
to style thetitle
of the modalcancelBtnStyle
to style thecancel button
This project was bootstrapped with Create React App.
In the project directory, you can run:
Runs the app in the development mode.
Open http://localhost:3000 to view it in the browser.
The page will reload if you make edits.
You will also see any lint errors in the console.
Launches the test runner in the interactive watch mode.
See the section about running tests for more information.
Builds the app for production to the build
folder.
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.
Your app is ready to be deployed!
See the section about deployment for more information.
Note: this is a one-way operation. Once you eject
, you can’t go back!
If you aren’t satisfied with the build tool and configuration choices, you can eject
at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except eject
will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
You don’t have to ever use eject
. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
You can learn more in the Create React App documentation.
To learn React, check out the React documentation.
This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
Mir Sujat