Modal
A modal is a dialog that intentionally calls for users attention. Models interrupt users workflow by design.
They are overlays that prevent users from interacting with the rest of the application until a specific action is taken. They can be disruptive because they require merchants to take an action before they can continue interacting with the rest of the site. It should be used thoughtfully and sparingly.
React
releasedVue
releasedElements
releasedAndroid
releasediOS
releasedExample
Usage
Design Guidelines
See Figma: Warp - Components / Modal
Accessibility
Modal needs either aria-label or aria-labelledby to be accessible to screen readers.
All dialogs must have a title. Titles appear in bold at the top of the dialog and use a few words to convey the outcome of what will happen if a user continues with an action. Use the property title for this.
Questions?
Feel free to ask any questions on usage in the Warp DS Slack channel: #nmp-warp-design-system
Frameworks
Import
You can import the component like so:
import { Modal } from '@warp-ds/react';
or import it individually to optimize your JS bundle size by adding only the components you need:
import { Modal } from '@warp-ds/react/components/modal'
Props
Required props
name | type | default | notes |
---|---|---|---|
children | Element | The modal contents | |
open | boolean | Whether the modal is open or not |
Optional Props
name | type | default | notes |
---|---|---|---|
title | string | A string or your own custom elements | |
left | boolean | Whether a default back button should render with an onDismiss() callback. It can also be your own custom element(s). | |
right | boolean | A default close button or your own custom elements | |
footer | Element | Buttons passed to the footer | |
className | string | Additional classes added to the container | |
id | string | An id for the container and ARIA attributes. A random id is generated if none is provided. | |
style | CSSProperties | Additional styles to the container. More info about CSSProperties | |
aria-label | number | Defines a string value that labels the current element. Must be set if neither | |
aria-labelledby | string | Identifies the element (or elements) that labels the current element. Must be set if neither | |
initialFocusRef | RefObject | A reference to the element that should be focused. By default it'll be the first interactive element. More info |
Events
name | when | ||
---|---|---|---|
onDismiss | () => void | Handler that is called when the user presses esc or clicks outside the modal. | |
onLeftClick | () => void | Handler that is called when the user clicks the default back button. Requires the |
Example
function Example() {
const [open, setOpen] = React.useState(false);
const [left, setLeft] = React.useState(true);
const [height, setHeight] = React.useState('68%');
const toggleModal = () => setOpen(!open);
return (
<>
<Button utility onClick={toggleModal}>
Open modal
</Button>
<Modal
left={left}
right
open={open}
onDismiss={toggleModal}
title="Hello title"
footer={
<Button primary onClick={toggleModal}>
Confirm
</Button>
}
style={{
'--w-modal-max-height': height,
'--w-modal-height': '100%',
}}
>
<div className="space-x-8">
<button
onClick={() => setHeight(height === '68%' ? '100%' : '68%')}
className="button button--utility button--small mb-32"
>
Modify height
</button>
<button
onClick={() => setLeft(!left)}
className="button button--utility button--small mb-32"
>
Toggle the back-button
</button>
</div>
<div>
<h1 className="h4 mb-16">This is a title for the content area</h1>
<p>
Life as a shorty shouldn't be so rough. Behold the bold soldier
control the globe slowly, proceeds to blow, swinging swords like
Shinobi. The game of chess, is like a swordfight, you must think
first before you move. My beats travel like a vortex through your
spine, to the top of your cerebral cortex. I smoke on the mic like
smoking Joe Frazier, the hell raiser, raising hell with the flavor.
</p>
<p>
I breaks it down to the bone gristle, Ill speaking Scud missile heat
seeking, Johnny Blazing. Protect Ya Neck, my sword still remain
imperial before I blast the mic, RZA scratch off the serial.
Shackling the masses with drastic rap tactics, graphic displays melt
the steel like blacksmiths. Perpendicular to the square we stay in
gold like Flair, escape from your dragon's lair in particular. Shame
on you when you stepped through to The Ol Dirty Bastard straight
from the Brooklyn Zoo. Protect Ya Neck, my sword still remain
imperial before I blast the mic, RZA scratch off the serial.
</p>
<p>
Life as a shorty shouldn't be so rough. Handcuffed in the back of a
bus, forty of us. Rae got it going on pal, call me the rap
assassinator, rhymes rugged and built like Schwarzenegger. My beats
travel like a vortex through your spine, to the top of your cerebral
cortex. Life as a shorty shouldn't be so rough. Well I'm a sire, I
set the microphone on fire, rap styles vary and carry like Mariah.
</p>
</div>
</Modal>
</>
);
}
Content
WARP guidelines state the following:
- The cancel action should always be on the left, while the main action is to the right.
Non dismissable modals
The onDismiss
prop is optional. It can be dropped to create a modal that won't respond to esc
key presses and/or clicking outside the modal.
function Example() {
const [open, setOpen] = React.useState(false);
const [mustAgree, setMustAgree] = React.useState(false);
const [hasAgreed, setHasAgreed] = React.useState(false);
const toggleModal = () => {
if (open && !hasAgreed) {
setMustAgree(true);
return;
}
setMustAgree(false);
setOpen(!open);
};
return (
<>
<Button utility onClick={toggleModal}>
Open modal
</Button>
<Modal
open={open}
onDismiss={hasAgreed ? toggleModal : undefined}
title="Non dismissable"
footer={
<>
{mustAgree && <p className="m-10">You must agree first!</p>}
<Button primary onClick={toggleModal}>
Save
</Button>
</>
}
>
<p>To go further, you need to agree to these bogus terms</p>
<Toggle
type="checkbox"
label="I agree"
checked={hasAgreed}
onChange={(state) => setHasAgreed(state)}
/>
</Modal>
</>
);
}
Customizing focus behavior
By default, the first interactive element in the modal will be focused when the modal opens. Use initialFocusRef
to customize this behavior. For instance, this can be used to focus a call-to-action button.
function Example() {
const [open, setOpen] = React.useState(false);
const focusRef = React.useRef();
const toggleModal = () => setOpen(!open);
return (
<>
<Button utility onClick={toggleModal}>
Open modal
</Button>
<Modal
open={open}
initialFocusRef={focusRef}
title="Customized focus behavior"
footer={
<>
<Button onClick={toggleModal} className="mr-12">
Cancel
</Button>
<Button primary ref={focusRef} onClick={toggleModal}>
Accept
</Button>
</>
}
>
<p>The call to action button has inital focus.</p>
</Modal>
</>
);
}