A modal is an element that shows a priority dialog above the current content, where the focus should be completely pointed to the information inside of it, blocking all elements underneath with an opaque overlay.
Example
function displayModal() {
const ModalButton = () => {
const { openModal, closeModal, updateModal } = useContext(ModalContext);
const text =
'One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin.';
const handleButtonClick = () => {
openModal({
content: text,
closeOnPrimaryClick: false,
primaryAction: {
label: 'Save',
kind: 'primary',
onClick: () => {
alert('Saved!');
updateModal({
title: 'Second title',
content: 'Some new content'
});
}
},
secondaryAction: {
label: 'Cancel',
kind: 'secondary',
onClick: closeModal
},
closeButtonAction: () => console.log('Close button clicked'),
size: 'medium',
title: 'Modal dialog',
testId: 'some-unique-identifier'
});
};
return <Button label="Open modal" onClick={handleButtonClick} />;
};
return (
<ModalProvider>
<ModalButton />
</ModalProvider>
);
}
Usage Rules
When setting the code to use a Modal, you will wrap the component tree with ModalProvider
.
import { ModalProvider } from '@adjust/components';
export default function() {
return (
<ModalProvider>
{...}
</ModalProvider>
);
}
Inside the ModalProvider
scope your code has access to openModal()
and closeModal()
via ModalContext
.
CloseModal()
is a direct instruction with no arguments, where OpenModal()
usage is shown on the first example. The CloseModal()
function will also call any code passed via onClose
property.
The ModalProvider
does not receive any property itself, while the openModal
function accepts all the properties documented below.
It is possible to close the Modal by pressing the ESC
key, on the keyboard
Variants
Custom Content
It is possible to use an element and/or a React component as content for the Dialog, as shown on the next example:
function displayModal() {
const TwoFactorDialog = () => {
const { openModal } = useContext(ModalContext);
const content = (
<div>
<p>
Add greater security to your dashboard with two-factor authentication.
Once enabled, you’ll receive a one-time access link every time you
sign in.
</p>
<div>
<Switch size="medium" aria-label="Two-Factor Authentication" />{' '}
Two-Factor Authentication
</div>
</div>
);
const twoFactorDialog = () => {
openModal({
content: content,
primaryAction: {
label: 'Done',
kind: 'primary'
},
size: 'medium',
title: `Manage two-factor authentication of your account for enhanced security`
});
};
return (
<>
<Button label="Two-Factor Authentication" onClick={twoFactorDialog} />
</>
);
};
return (
<ModalProvider>
<TwoFactorDialog />
</ModalProvider>
);
}
Primary Action
The primary action primaryAction
is optional. It will execute the code which is added to primaryAction.onClick
and then automatically close the Modal as default.
- Using
closeOnPrimaryClick
as Modal
prop to prevent the Modal from closing after clicking on the primary button. - Using
closeModal()
in primaryAction.onClick
to close the modal.
Secondary Action
The secondary action secondaryAction
is optional. This action gives you freedom to decide either to close or not. If you want to close, make sure to call closeModal()
inside your custom secondaryAction.onClick
, just like the first example.
Sizes
It is possible to pick between three different widths of the modal's dialog: small
, medium
(default) and large
.
You can see them on the following example:
function displayModal() {
const ModalButtons = () => {
const { openModal } = useContext(ModalContext);
const text = {
small: 'One morning, Gregor Samsa woke up.',
medium:
'One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin.',
large:
'One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin. He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections.'
};
const handleButtonClick = (size) => {
openModal({
content: text[size],
primaryAction: {
label: 'Close',
kind: 'primary'
},
size: size,
title: `Modal dialog: ${size}`
});
};
return (
<>
<Button
label="Small modal"
onClick={() => handleButtonClick('small')}
/>
<Button
label="Medium modal"
onClick={() => handleButtonClick('medium')}
/>
<Button
label="Large modal"
onClick={() => handleButtonClick('large')}
/>
<Button
label="X-Large modal"
onClick={() => handleButtonClick('x-large')}
/>
</>
);
};
return (
<ModalProvider>
<ModalButtons />
</ModalProvider>
);
}
Static Height
You can set the height of Modal content by adding prop staticHeight
.
function displayModal() {
const ModalButtons = () => {
const { openModal } = useContext(ModalContext);
const longText = `There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc.`
const handleButtonClick = () => {
openModal({
content: longText,
primaryAction: {
label: 'Close',
kind: 'primary'
},
size: 'small',
title: 'Static Height',
staticHeight: '400px'
});
};
return (
<Button
label="Open modal"
onClick={handleButtonClick}
/>
);
};
return (
<ModalProvider>
<ModalButtons />
</ModalProvider>
);
}
Update Modal
You can update existing Modal by using updateModal()
. It will update the existing Modal
props.
function displayModal() {
const ModalButton = () => {
const { openModal, closeModal, updateModal } = useContext(ModalContext);
const text =
'One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin.';
const handleButtonClick = () => {
openModal({
content: text,
closeOnPrimaryClick: false,
primaryAction: {
label: 'Save',
kind: 'primary',
onClick: () => {
updateModal({
title: 'Second title',
content: 'Some new content'
});
}
},
secondaryAction: {
label: 'Cancel',
kind: 'secondary',
onClick: closeModal
},
closeButtonAction: () => console.log('Close button clicked'),
size: 'medium',
title: 'Modal dialog',
testId: 'some-unique-identifier'
});
};
return <Button label="Open modal" onClick={handleButtonClick} />;
};
return (
<ModalProvider>
<ModalButton />
</ModalProvider>
);
}
You can also overwrite all Modal
props by passing true
as the second argument in updateModal()
.
function displayModal() {
const ModalButton = () => {
const { openModal, closeModal, updateModal } = useContext(ModalContext);
const text =
'One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin.';
const handleButtonClick = () => {
openModal({
content: text,
closeOnPrimaryClick: false,
primaryAction: {
label: 'Save',
kind: 'primary',
onClick: () => {
updateModal(
{
title: 'Second title',
content: 'Some new content',
primaryAction: {
label: 'Close',
kind: 'primary',
onClick: closeModal
}
},
true
);
}
},
secondaryAction: {
label: 'Cancel',
kind: 'secondary',
onClick: closeModal
},
closeButtonAction: () => console.log('Close button clicked'),
size: 'medium',
title: 'Modal dialog',
testId: 'some-unique-identifier'
});
};
return <Button label="Open modal" onClick={handleButtonClick} />;
};
return (
<ModalProvider>
<ModalButton />
</ModalProvider>
);
}
Examples
Modal open state
You can get the open state of the modal with isModalOpen
from the ModalContext
function displayModal() {
const ModalButtons = () => {
const { openModal, isModalOpen } = useContext(ModalContext);
console.log({ isModalOpen });
const content =
'One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin. He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections.';
const handleButtonClick = () => {
openModal({
content,
primaryAction: {
label: 'Close',
kind: 'primary'
},
size: 'large',
title: 'Modal dialog'
});
};
return (
<div>
<p>{isModalOpen ? 'Modal is open' : 'Modal is closed'}</p>
<Button label="Open modal" onClick={handleButtonClick} />
</div>
);
};
return (
<ModalProvider>
<ModalButtons />
</ModalProvider>
);
}
Update loading state
You can update the loading state of a button by using updateModal()
.
function displayModal() {
const ModalButton = () => {
const { openModal, closeModal, updateModal } = useContext(ModalContext);
const text =
'One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin.';
const primaryAction = {
label: 'Save',
kind: 'primary',
isLoading: false,
disabled: false,
onClick: () => {
updateModal({
primaryAction: {
...primaryAction,
...{ isLoading: true, disabled: true }
}
});
}
};
const handleButtonClick = () => {
openModal({
content: text,
closeOnPrimaryClick: false,
primaryAction: primaryAction,
secondaryAction: {
label: 'Cancel',
kind: 'secondary',
onClick: closeModal
},
closeButtonAction: () => console.log('Close button clicked'),
size: 'medium',
title: 'Modal dialog',
testId: 'some-unique-identifier'
});
};
return <Button label="Open modal" onClick={handleButtonClick} />;
};
return (
<ModalProvider>
<ModalButton />
</ModalProvider>
);
}
Props
The object structure for individual modal items passed into openModal
:
|
title * Title of the Modal's dialog | | — |
content * Content of the Modal's dialog | | — |
primaryAction Primary button for the Dialog component. See the Button component for more info | | — |
secondaryAction Secondary and optional button for the Dialog component.
See the Button component for more info | | — |
closeButtonAction The handler will be called only on clicking Close button | | — |
onClose The handler will be called when the Modal is closed | | — |
onUpdate The handler will be called when the Modal is updated | ((dialog: DialogComponentProps) => void)
| — |
size Size of the Modal's dialog | "small" | "medium" | "large" | "x-large"
| "medium" |
closeOnPrimaryClick Use this prop to prevent the Modal's dialog from closing after clicking on the primary button | | true |
staticHeight Static height of Modal's content and support scrollable. | | — |
testId Unique identifier for Pendo tagging to be translated into data-testid attribute on Modal Actions | | — |
* - the prop is required. |