Features
- Show an illustration or photograph to amplify communication visually
- Can be used for both single and multi step flows
- Supports both light grey and pink background colors
When to use
Modal split is used for explaining things - such as introducing customers to new concepts or set up features, communicating in-product updates, or encouraging specific actions or behaviours.
Promote feature
Before a customer has access to a feature, we often use a modal split to highlight the benefits, and explain why this would be a good feature for them.
const Example = () => {
const [showDialog, setShowDialog] = React.useState(false)
const open = () => setShowDialog(true)
const close = () => setShowDialog(false)
return (
<>
<Button onClick={open}>Open modal</Button>
<ModalSplit isOpen={showDialog} onDismiss={close}>
<ModalSplit.Content>
<ModalSplit.Body>
<ModalSplit.Title>Direct Reimbursements</ModalSplit.Title>
<Stack space={16}>
<Tag variant="green">Included in your Essentials Plan</Tag>
<div>
<ModalSplit.SectionTitle>How it works</ModalSplit.SectionTitle>
<ModalSplit.Text>
Admins send reimburse employees directly from the Pleo Wallet to
their bank account/personal card. Employees can reimburse
themselves if you choose.
</ModalSplit.Text>
</div>
<div>
<ModalSplit.SectionTitle>Benefits</ModalSplit.SectionTitle>
<List>
<List.Item>
<ListIcon as={Check} />
Employees get their money back faster
</List.Item>
<List.Item>
<ListIcon as={Check} />
You spend less time in Pleo
</List.Item>
<List.Item>
<ListIcon as={Check} />
Out-of-pocket expenses can be filed faster with OCR
</List.Item>
</List>
</div>
<div>
<ModalSplit.SectionTitle>What does it cost</ModalSplit.SectionTitle>
<ModalSplit.Text>
0.9% of the reimbursement amount, never exceeding 1 EUR per
transfer. <Link href="">Learn more</Link>
</ModalSplit.Text>
</div>
</Stack>
</ModalSplit.Body>
<ModalSplit.Actions>
<ModalSplit.NextButton onClick={close}>Switch on</ModalSplit.NextButton>
</ModalSplit.Actions>
</ModalSplit.Content>
<ModalSplit.IllustrationContainer>
<ModalSplit.Illustration p={40}>
<Key width="100%" height="100%" />
</ModalSplit.Illustration>
</ModalSplit.IllustrationContainer>
</ModalSplit>
</>
)
}
render(<Example />)Photography
Using photography in a Modal Split can boost feature adoption and drive resulting spend by attracting attention and adding context. Rarely used in the product, photos draw users in, suggesting where and how the feature fits and creating a positive emotional tone. Paired with simplified UI, they can help users quickly grasp the value proposition.
If a photograph is purely decorative, set
the alt attribute to an empty string (alt="") to ensure it’s ignored by screen readers.
Otherwise, use descriptive alt text to convey the essential content or purpose of the photograph.
const Example = () => {
const [showDialog, setShowDialog] = React.useState(false)
const open = () => setShowDialog(true)
const close = () => setShowDialog(false)
return (
<>
<Button onClick={open}>Open modal</Button>
<ModalSplit isOpen={showDialog} onDismiss={close}>
<ModalSplit.Content>
<ModalSplit.Body>
<ModalSplit.Title>
Guidelines for Client Dinners are ready to go!
</ModalSplit.Title>
<Stack space={16}>
<ModalSplit.Text>
Published guidelines will be available to the employees that can use
this category. On the mobile app, they can:
</ModalSplit.Text>
<List>
<List.Item>
<ListIcon as={Check} />
See the guidelines in the original form
</List.Item>
<List.Item>
<ListIcon as={Check} />
Ask questions about spending
</List.Item>
</List>
</Stack>
</ModalSplit.Body>
<ModalSplit.Actions>
<ModalSplit.NextButton onClick={close}>Publish</ModalSplit.NextButton>
</ModalSplit.Actions>
</ModalSplit.Content>
<ModalSplit.Photograph>
<img src={photo} alt="" />
</ModalSplit.Photograph>
</ModalSplit>
</>
)
}
render(<Example />)Set up features
We use the modal to take customers through step-based journeys to set up features and present key concepts that need configuring, for features to be ready for use.
For multi step flows, step indicators in the form of "dots" are shown to communicate the stage customers are at, setting expectations for the duration of the journey to completion. We recommend breaking flows into a maximum of 3 to 4 steps.
const Example = () => {
const steps = [{stepId: 'reimbursements'}, {stepId: 'expenses'}, {stepId: 'overview'}]
const {activeStep, setActiveStep, nextStep, previousStep} = useModalSplitSteps({
steps: steps,
initialActiveStep: 'reimbursements',
})
const [showDialog, setShowDialog] = React.useState(false)
const open = () => setShowDialog(true)
const close = () => {
setShowDialog(false)
setActiveStep('reimbursements')
}
return (
<>
<Button variant="primary" onClick={open}>
Open modal
</Button>
<ModalSplit isOpen={showDialog} onDismiss={close}>
<ModalSplit.Content>
<ModalSplit.StepIndicator
steps={steps}
activeStep={activeStep}
onClickStep={setActiveStep}
/>
<ModalSplit.Steps activeStepId={activeStep}>
<ModalSplit.Step stepId="reimbursements">
<ModalSplit.Body>
<ModalSplit.Title>What are Pleo Reimbursements?</ModalSplit.Title>
<ModalSplit.Text>
Enable Reimbursements and keep track of all out-of-pocket
expenses and purchases made with withdrawn company cash.
</ModalSplit.Text>
</ModalSplit.Body>
<ModalSplit.Actions>
<ModalSplit.NextButton onClick={nextStep}>
Next
</ModalSplit.NextButton>
</ModalSplit.Actions>
</ModalSplit.Step>
<ModalSplit.Step stepId="expenses">
<ModalSplit.Body>
<ModalSplit.Title>
Submit expenses on web or mobile app
</ModalSplit.Title>
<ModalSplit.Text>
Employees can add expenses at any time on the web or mobile app.
The employee balance will reflect all expenses and display the
amount owed to them or owed to the company.
</ModalSplit.Text>
</ModalSplit.Body>
<ModalSplit.Actions>
<ModalSplit.BackButton onClick={previousStep} />
<ModalSplit.NextButton onClick={nextStep}>
Next
</ModalSplit.NextButton>
</ModalSplit.Actions>
</ModalSplit.Step>
<ModalSplit.Step stepId="overview">
<ModalSplit.Body>
<ModalSplit.Title>
Overview of outstanding and settled transactions
</ModalSplit.Title>
<ModalSplit.Text>
Admin can quickly check outstanding employee balances.
</ModalSplit.Text>
<ModalSplit.Text space={16}>
Reimburse and receive money from employees.
</ModalSplit.Text>
</ModalSplit.Body>
<ModalSplit.Actions>
<ModalSplit.BackButton onClick={previousStep} />
<ModalSplit.NextButton onClick={close}>Done</ModalSplit.NextButton>
</ModalSplit.Actions>
</ModalSplit.Step>
</ModalSplit.Steps>
</ModalSplit.Content>
<ModalSplit.IllustrationContainer>
<ModalSplit.Steps activeStepId={activeStep}>
<ModalSplit.Step stepId="reimbursements">
<ModalSplit.Illustration p={40}>
<PaperClip width="100%" height="100%" />
</ModalSplit.Illustration>
</ModalSplit.Step>
<ModalSplit.Step stepId="expenses">
<ModalSplit.Illustration p={40}>
<Card width="100%" height="100%" />
</ModalSplit.Illustration>
</ModalSplit.Step>
<ModalSplit.Step stepId="overview">
<ModalSplit.Illustration p={40}>
<Balance width="100%" height="100%" />
</ModalSplit.Illustration>
</ModalSplit.Step>
</ModalSplit.Steps>
</ModalSplit.IllustrationContainer>
</ModalSplit>
</>
)
}
render(<Example />)Communicate updates
When there are new in-product updates e.g. changes to the UI, we use the modal to communicate to customers why they happened and how they can benefit from them.
const Example = () => {
const steps = [
{stepId: 'look'},
{stepId: 'tabs'},
{stepId: 'filters'},
{stepId: 'sort'},
{stepId: 'place'},
]
const {activeStep, setActiveStep, nextStep, previousStep} = useModalSplitSteps({
steps: steps,
initialActiveStep: 'look',
})
const [showDialog, setShowDialog] = React.useState(false)
const open = () => setShowDialog(true)
const close = () => setShowDialog(false)
return (
<>
<Button onClick={open}>Open modal</Button>
<ModalSplit isOpen={showDialog} onDismiss={close}>
<ModalSplit.Content>
<ModalSplit.StepIndicator
steps={steps}
activeStep={activeStep}
onClickStep={setActiveStep}
/>
<ModalSplit.Steps activeStepId={activeStep}>
<ModalSplit.Step stepId="look">
<ModalSplit.Body>
<ModalSplit.Title>We've got a new look.</ModalSplit.Title>
<ModalSplit.Text space={16}>
We have been working on some huge improvements in the partner
portal. The new look and features should make your life as a
partner a lot easier and quicker.
</ModalSplit.Text>
<ModalSplit.Text>
We want you and your team to spend your time on what really
matters the most.
</ModalSplit.Text>
</ModalSplit.Body>
<ModalSplit.Actions>
<ModalSplit.NextButton onClick={nextStep}>
Continue
</ModalSplit.NextButton>
</ModalSplit.Actions>
</ModalSplit.Step>
<ModalSplit.Step stepId="tabs">
<ModalSplit.Body>
<ModalSplit.Title>We've added tabs</ModalSplit.Title>
<ModalSplit.Text>
To give you a better overview of your invites and clients, we
have introduced tabs. You can now easily find all of your
clients and pending invites by just switching between the
different tabs.
</ModalSplit.Text>
</ModalSplit.Body>
<ModalSplit.Actions>
<ModalSplit.BackButton onClick={previousStep} />
<ModalSplit.NextButton onClick={nextStep}>
Continue
</ModalSplit.NextButton>
</ModalSplit.Actions>
</ModalSplit.Step>
<ModalSplit.Step stepId="filters">
<ModalSplit.Body>
<ModalSplit.Title>Introducing filters</ModalSplit.Title>
<ModalSplit.Text space={16}>
As part of the new look of the client page, we are introducing
filters to help with your workflows.
</ModalSplit.Text>
<ModalSplit.Text>
You can now filter clients by missing receipts, expenses ready
for export as well as low wallet balance.
</ModalSplit.Text>
</ModalSplit.Body>
<ModalSplit.Actions>
<ModalSplit.BackButton onClick={previousStep} />
<ModalSplit.NextButton onClick={nextStep}>
Continue
</ModalSplit.NextButton>
</ModalSplit.Actions>
</ModalSplit.Step>
<ModalSplit.Step stepId="sort">
<ModalSplit.Body>
<ModalSplit.Title>Sort your clients easily</ModalSplit.Title>
<ModalSplit.Text>
Filters are not the only new addition. You can now also sort
your clients as well. Low wallet balance, missing receipts,
expenses ready or a simple alphabetical order? We have got you
covered.
</ModalSplit.Text>
</ModalSplit.Body>
<ModalSplit.Actions>
<ModalSplit.BackButton onClick={previousStep} />
<ModalSplit.NextButton onClick={nextStep}>
Continue
</ModalSplit.NextButton>
</ModalSplit.Actions>
</ModalSplit.Step>
<ModalSplit.Step stepId="place">
<ModalSplit.Body>
<ModalSplit.Title>All in one place</ModalSplit.Title>
<ModalSplit.Text space={16}>
All that client information like their expenses, wallet balance,
assigned bookkeepers and more?
</ModalSplit.Text>
<ModalSplit.Text>
Tap on view client details and you can easily view them all in
one place together. Smooth.
</ModalSplit.Text>
</ModalSplit.Body>
<ModalSplit.Actions>
<ModalSplit.BackButton onClick={previousStep} />
<ModalSplit.NextButton onClick={close}>
Let's go
</ModalSplit.NextButton>
</ModalSplit.Actions>
</ModalSplit.Step>
</ModalSplit.Steps>
</ModalSplit.Content>
<ModalSplit.IllustrationContainer>
<ModalSplit.Steps activeStepId={activeStep}>
<ModalSplit.Step stepId="look">
<ModalSplit.Illustration p={40}>
<Star width="100%" height="100%" />
</ModalSplit.Illustration>
</ModalSplit.Step>
<ModalSplit.Step stepId="tabs">
<ModalSplit.Illustration p={40}>
<Cursor width="100%" height="100%" />
</ModalSplit.Illustration>
</ModalSplit.Step>
<ModalSplit.Step stepId="filters">
<ModalSplit.Illustration p={40}>
<Target width="100%" height="100%" />
</ModalSplit.Illustration>
</ModalSplit.Step>
<ModalSplit.Step stepId="sort">
<ModalSplit.Illustration p={40}>
<Optimization width="100%" height="100%" />
</ModalSplit.Illustration>
</ModalSplit.Step>
<ModalSplit.Step stepId="place">
<ModalSplit.Illustration p={40}>
<Synergy width="100%" height="100%" />
</ModalSplit.Illustration>
</ModalSplit.Step>
</ModalSplit.Steps>
</ModalSplit.IllustrationContainer>
</ModalSplit>
</>
)
}
render(<Example />)Encourage actions
We also use the modal to encourage that customers take certain actions e.g. top-up wallet, to get the most out of the the Pleo product.
We commonly use Action banners to encourage and direct customers to take different actions to get the most out of Pleo.
const Example = () => {
const [showDialog, setShowDialog] = React.useState(false)
const open = () => setShowDialog(true)
const close = () => setShowDialog(false)
return (
<>
<Button onClick={open}>Open modal</Button>
<ModalSplit isOpen={showDialog} onDismiss={close}>
<ModalSplit.Content>
<ModalSplit.Body>
<ModalSplit.Title>Your account is on hold</ModalSplit.Title>
<ModalSplit.Text space={16}>
There isn't enough money in your wallet to pay your Pleo subscription
fees. The amount owed is 245,00 DKK. <Link href="">View invoice</Link>
</ModalSplit.Text>
<ModalSplit.Text>
To reactivate your account, simply top up your wallet. We recommend
adding enough funds to cover your team's expenses for the next month or
two. <Link href="">View wallet</Link>
</ModalSplit.Text>
</ModalSplit.Body>
<ModalSplit.Footer>
Don't want to continue? <Link href="">Export data</Link> or{' '}
<Link href="">Close account</Link>
</ModalSplit.Footer>
</ModalSplit.Content>
<ModalSplit.IllustrationContainer variant="pink">
<ModalSplit.Illustration p={40}>
<Padlock color="grey" width="100%" height="100%" />
</ModalSplit.Illustration>
</ModalSplit.IllustrationContainer>
</ModalSplit>
</>
)
}
render(<Example />)Best practices
Illustration and background colour
Use an illustration from
@pleo-io/telescope-illustrations to amplify visual communication. Pick the object that best
carries the message of the copy next to it.
Every illustration comes in a pink and a grey variant. Choose the variant based on the background, so the illustration stands out instead of blending in:
- On the default grey background, use the pink illustration (the default variant).
- On the pink background (
variant="pink"), use the grey illustration (color="grey").
For multi-step flows, keep the background colour consistent across all steps. Mixing colours can imply additional meanings or suggest that some steps are more important than others. If unsure, default to grey.
Can't find an illustration that works for your use case? Request a new one from the brand design team.
Photography
Collaborate with brand design when using photographs in a Modal Split. It's brand design's responsibility to curate and export the photographs. You can request new photographs from the brand design team by filling out this form.
When using simplified UI in a photography, make sure to position it in the top left corner. This is to ensure that it doesn't get cropped out when the modal is displayed on smaller screens.
Do's and don'ts
Accessibility
Telescope's modal primitives use Radix Dialog to implement the WAI-ARIA principles of Dialog (Modal).
Related components
- Drawer: A panel that slides out from the edge of the screen to focus a user's attention on completing a task or viewing details about an item.
- Modal: A page overlay that displays information and blocks interaction with the page until an action is taken or the modal is dismissed.
- Page: A collection of components which let you compose a page in our web application.
- Popover: A small overlay that opens on demand. Popovers allow users to access additional content and actions without cluttering the page.