Overview
<div className="ta-center m-x-auto" style={{width:420}}>
<img src={TitanPhone} width={190} height={107} className="m-b-2" />
<Headline>Looks like Reports haven't been set up yet</Headline>
<BodyText subdued>Set it up today to start improving your business through our integrated system.</BodyText>
<Button primary className="m-t-3">Start Setup</Button>
</div>
Empty states can be employed to:
- Make users aware that a feature is not configured for use.
- Communicate that there is no data to display.
- Act as a placeholder for regions in the app left blank intentionally.
- Convey an error state, like a server response error, i.e., 404 or 500.
- Display empty search results.
- Help users onboard and encourage them to interact with the application
- Prevent users from having to “back up” and go in a different direction
Headlines
Empty states headlines should be proactive and helpful. Focus on the task ahead that will help them fill the empty state, rather than calling out what’s missing from the screen. Calling out what’s missing can work in description text, but it’s always better to give information about the filled state of the screen.
Good Empty State - Headline Gives Proactive Direction
<div className="ta-center m-x-auto" style={{width:420}}>
<img src={BookmarksBlue} width={105} height={94} className="m-b-3" />
<Headline>Bookmark Your Reports</Headline>
<BodyText subdued>Bookmarked reports will appear here for quick access.</BodyText>
<Button primary fill="outline" className="m-t-3">Learn More</Button>
</div>
Bad Empty State - Headline Isn't Helpful
<div className="ta-center m-x-auto" style={{width:420}}>
<img src={BookmarksBlue} width={105} height={94} className="m-b-3" />
<Headline>No Bookmarks</Headline>
<BodyText subdued>You haven't bookmarked any reports yet.</BodyText>
<Button primary fill="outline" className="m-t-3">Learn More</Button>
</div>
Compared to Banners
Empty states differ from banners in that they are not intended to promote or advertise new features or functionality.
<div className="ta-center m-x-auto" style={{width:420}}>
<img src={TitanPhone} width={190} height={107} className="m-b-2" />
<Headline>Looks like Reports haven't been set up yet</Headline>
<BodyText subdued>Set it up today to start improving your business through our integrated system.</BodyText>
<Button primary className="m-t-3">Start Setup</Button>
</div>
Good Empty State - Helpful Content
<div className="ta-center m-x-auto" style={{width:420}}>
<img src={TitanPhone} width={190} height={107} className="m-b-2" />
<Headline>Get Reports</Headline>
<BodyText subdued>Drive higher booking rates, increase revenue, and boost efficiency with a fully-integrated, cloud-based report system.</BodyText>
<Button primary className="m-t-3">Upgrade Now</Button>
</div>
Bad Empty State - It's a Marketing Banner
Compared to Introduction Screens
Empty states differ from introduction screens in the headline wording. They should give the user an instruction. Additionally, introduction screens will often be the first screen after launching a wizard, whereas an empty state would not likely be used in that scenario.
<div className="ta-center m-x-auto" style={{width:420}}>
<img src={PayrollProfiles} width={150} height={80} className="m-b-3" />
<Headline>Set Up Your Reports</Headline>
<BodyText subdued>You can now create reports with rules based on your business needs. No more complex spreadsheets just to keep track of your business health.</BodyText>
<Button primary className="m-t-3">Get Started</Button>
</div>
Good Empty State - Headline Gives Directive
<div className="ta-center m-x-auto" style={{width:420}}>
<img src={PayrollProfiles} width={150} height={80} className="m-b-3" />
<Headline>Welcome to Your Reports Walkthrough</Headline>
<BodyText subdued>We will now teach you how to create reports with rules base don your business needs. This walkthrough will take 5-10 minutes.</BodyText>
<Button primary className="m-t-3">Get Started</Button>
</div>
Bad Empty State - It's Worded Like an Introduction Screen
Types of Empty States
First Time Setup
During the initial onboarding process, the user will encounter a lot of empty states. We should try to make these empty states fun and encouraging with an approachable tone and helpful content so the user feels supported and confident through the set up process. Since these empty states will only be seen once or twice, they can be celebratory and decorative without being overkill.
Educate the User
Sometimes the purpose of the empty state is to teach the user how to fill it by explaining what to do next or using a CTA to link them to a walk-through. Once the user learns how to fill the screen, there’s a good chance it may not be empty again. If it is likely to be empty again, an additional Recurring Empty State may be needed.
- Keep explanations concise. Any longer than 200 characters and/or 4 lines of text should be made into a help article or walk-through.
- If linking to a help article or walk-through, be sure to prime the user on what each will entail.
- Illustrations are encouraged. See Illustrations for more information on how to employ them.
- Keep the tone friendly and encouraging.
<div className="ta-center m-x-auto" style={{width:420}}>
<img src={CustomizeAudience} width={150} height={82} className="m-b-2" />
<Headline>Build a Custom Report</Headline>
<BodyText subdued>Click "Add Filter" in the left column to include or exclude specific characteristics of your audience. You can nest segment logic and have as many segments as you need.</BodyText>
</div>
<div className="ta-center m-x-auto" style={{width:420}}>
<img src={CustomizeAudience} width={150} height={82} className="m-b-2" />
<Headline>Build a Custom Report</Headline>
<BodyText subdued>Not sure how to get started? Let us take you through a quick walk-through.</BodyText>
<Button primary outline className="m-t-3">Learn More</Button>
</div>
Quick Setup
Sometimes the purpose of the empty state is to bring the user through a setup flow as quickly as possible. Once the user completes the setup flow, there’s a good chance the empty state will never show up again. If it is likely to be empty again, an additional Recurring Empty State may be needed.
- Use a clear headline and CTA to initiate the setup flow.
- Make sure to inform the user about what info/documents they need on hand to complete the setup.
- Illustrations are encouraged.
- Keep the tone friendly and encouraging.
<div className="ta-center m-x-auto" style={{width:420}}>
<img src={PayrollProfiles} width={150} height={79} className="m-b-2" />
<Headline>Set Up Your Report</Headline>
<BodyText subdued>You can now create reports with rules based on your business needs. Then assign employees to each report. No more complex spreadsheets just to keep track of your business health.</BodyText>
<Button primary className="m-t-3">Get Started</Button>
</div>
<div className="ta-center m-x-auto" style={{width:420}}>
<img src={PayrollProfiles} width={150} height={79} className="m-b-2" />
<Headline>Set Up Your Report</Headline>
<BodyText subdued>Say goodbye to complex spreadsheets. You can now create and assign reports with custom rules.</BodyText>
<Card className="m-t-3 m-x-auto" style={{width:350}}>
<BodyText bold className="m-b-1">Before starting, grab these for reference:</BodyText>
<BodyText>- Employee Information<br />- Company Information</BodyText>
</Card>
<Button primary className="m-t-3">Get Started</Button>
</div>
Recurring Empty States
After setup has been completed, some screens/sections display empty states as a natural state of the screen/section or as an error message. Since these empty states can happen frequently, their main goal is to communicate information, and don’t need to be celebratory or decorative. Recurring empty states may or may not have a CTA, depending on whether the empty state is within the user’s control.
Communicate Functional Feedback
The purpose of some recurring empty states is to show functional feedback about the information on that screen. The functional feedback is usually neutral, but it can be positive or negative in some situations.
Neutral Functional Feedback
The most common type of recurring empty state feedback. If whether or not a user populates a screen/section is up to preference and/or doesn’t inhibit any workflows, neutral functional feedback is appropriate. In some instances, a positive empty state that occurs frequently may be displayed as “neutral” in order to tone it down visually.
Recommendations:
- Keep feedback concise and direct.
- If a CTA is applicable, use an in-line link.
- Use grayscale / subdued text.
- A grayscale icon may be used to increase understanding but is not required.
- Do not use illustrations.
<div className="ta-center m-x-auto" style={{width:420}}>
<BodyText subdued size="small">You have no billing history. When an invoice is complete, it will appear here.</BodyText>
</div>
<div className="ta-center m-x-auto" style={{width:420}}>
<Icon name="money_off" size={32} className="m-b-2 c-neutral-80" />
<BodyText subdued size="small">You have no billing history. When an invoice is complete, it will appear here. <Link primary>View active invoices.</Link></BodyText>
</div>
Negative Functional Feedback
Functional feedback is negative when workflows are inhibited by the empty state. The user may not be able to immediately move forward until the empty state is resolved, or the empty state could have potential negative impact on future workflows or processes. In these instances, the user should always have an explanation on what to do next, or an in-line CTA to help them resolve the empty state as quickly as possible.
- Keep feedback concise and direct.
- Must provide instructions or use a CTA that helps the user resolve the empty state.
- Use grayscale / subdued text.
- Must use a red icon that denotes warning or caution.
- Do not use illustrations.
<div className="ta-center m-x-auto" style={{width:420}}>
<Icon name="not_interested" size={32} className="m-b-2 c-red-500" />
<BodyText subdued size="small">No results found. Try another search or create a new report by clicking the button above.</BodyText>
</div>
<div className="ta-center m-x-auto" style={{width:420}}>
<Icon name="not_interested" size={32} className="m-b-2 c-red-500" />
<BodyText subdued size="small">No results found. Try another search or <Link primary>create a new report.</Link></BodyText>
</div>
Positive Functional Feedback
If the empty state is the desired state for the screen/section, the functional feedback should be positive. Since the feedback is positive, it could be a celebratory moment and an illustration may be appropriate. On the other hand, some positive empty states that occurs frequently may be displayed as “neutral” in order to tone them down visually.
- Keep feedback concise with an encouraging tone.
- If a CTA is applicable, use an in-line link.
- Use grayscale / subdued text.
- A full color icon may be used to increase understanding but is not required.
- An illustration may be used.
- Can follow the appearance recommendations for Neutral Functional Feedback.
<div className="ta-center m-x-auto" style={{width:420}}>
<Icon name="check_circle_outline" size={32} className="m-b-2 c-blue" />
<BodyText subdued size="small">Your report is up-to-date! Check back later for new updates.</BodyText>
</div>
<div className="ta-center m-x-auto" style={{width:420}}>
<img src={Book} width={130} height={115} className="m-b-2" />
<BodyText subdued size="small">Your report is up-to-date! Check back later for new updates. To see the history of changes, <Link primary>view your sync log.</Link></BodyText>
</div>
Empty States Outside of User's Control
Some empty states are caused by something outside of the user’s control. Something may be processing by ServiceTitan or a third-party vendor, or next steps may be dependent on a customer or another employee.
- Be transparent about what the empty state is, who is responsible for resolving it, and when that resolution may occur.
- Keep tone friendly and encouraging.
- Follow appearance recommendations accordingly for a first time setup or a recurring empty state (positive or neutral feedback).
- A full color or grayscale icon may be used to increase understanding but is not required.
- An illustration may be used.
<div className="ta-center m-x-auto" style={{width:420}}>
<img src={Financing} width={150} height={114} className="m-b-2" />
<Headline>You Account is Being Migrated</Headline>
<BodyText subdued>We are working on setting up your account. Verifying the information can take up to 3 business days. You will receive an email when your account is ready.</BodyText>
</div>
<div className="ta-center m-x-auto" style={{width:420}}>
<Icon name="build" size={32} className="m-b-2 c-neutral-80" />
<BodyText subdued>This account is going through routine maintenance. Your connection should resume as normal in a couple hours.</BodyText>
</div>
Error Empty States
Error empty states may occur due to a server issue (like a 404 or 500 error), or the user’s internet access could be interrupted by a poor connection.
- Be transparent about what the empty state is, who is responsible for resolving it, and when that resolution may occur.
- Must provide instructions or use a CTA that helps the user resolve the empty state.
- Follow appearance recommendations accordingly for a first time setup or a recurring empty state (positive or neutral feedback).
- A full color or grayscale icon may be used to increase understanding but is not required.
- An illustration may be used.
<div className="ta-center m-x-auto" style={{width:420}}>
<img src={Search} width={135} height={115} className="m-b-2" />
<Headline>We Didn't Catch That</Headline>
<BodyText subdued>The server didn't recognize your request. We are currently investigating the problem. Go back or <Link primary>try again.</Link></BodyText>
<Button primary outline className="m-t-3">Go Back</Button>
</div>
<div className="ta-center m-x-auto" style={{width:420}}>
<Icon name="error" size={32} className="m-b-2 c-neutral-80" />
<BodyText subdued>The server didn't recognize your request. We are currently investigating the problem. Go back or <Link primary>try again.</Link></BodyText>
</div>
Additional Content
Starter Content
To help users new to an app or section, screens which would otherwise be empty can be populated with starter content. Starter content allows users to begin using an app right away, making it easier for them to learn about what an app has to offer.
- Starter content is best for features that store content (such as Pricebook), or create templated content (such as Marketing Pro).
- Use content that has broad appeal and demonstrates primary features.
- Give users the ability to delete and replace starter content.
- If possible, provide content that's personalized.
const ExampleCard = ({children, icon, title, text}) => {
const [hover, setHover] = React.useState();
return (
<Card
className="flex-grow-1 flex-basis-0 d-f justify-content-center align-content-stretch"
active={hover}
raised={hover}
onMouseEnter={()=>setHover(true)}
onMouseLeave={()=>setHover(false)}
hoverable
>
<Card.Section>
<Stack spacing={2}>
<Stack.Item shrink={0}><Icon name={icon} className="c-neutral-80" /></Stack.Item>
<Stack.Item shrink={1}>
<Headline size="small">{title}</Headline>
<BodyText size="xsmall" subdued>{text}</BodyText>
</Stack.Item>
</Stack>
</Card.Section>
</Card>
);
};
const EmptyState = (
<div className="ta-center m-x-auto">
<div className="m-x-auto m-b-4" style={{width:420}}>
<Headline>Welcome to Reports</Headline>
<BodyText subdued>You don't have any reports. Here are some suggestions to get started with your first one.</BodyText>
</div>
<Stack spacing={3}>
<ExampleCard
icon="build"
title="Unsold Estimates"
text="Find and target open estimates. Leave no opportunity behind by creating custom parameters with your audience."
/>
<ExampleCard
icon="book"
title="Expiring Memberships"
text="Automatically reach out to customers with soon to expire memberships. Allow customers to see what memberships will expire and when. Prompt them to take action and renew."
/>
</Stack>
<Stack spacing={3} className="m-t-3">
<ExampleCard
icon="pause"
title="Idle Account"
text="Follow up with existing customers who have no recent activity in ServiceTitan. Customize the date parameter to find customers who have not called or booked a job."
/>
<ExampleCard
icon="alarm"
title="Aging Equipment"
text="Target customers with specific equipment. Let them know you're aware of their home and encourage them to take the next step in protecting their home."
/>
</Stack>
</div>
);
render (EmptyState)
Educational Content
If the purpose of the screen isn't easily conveyed through an image and tagline, consider showing educational content instead. Educational content helps users understand what a feature will be able to do once it has content.
- Make it possible to dismiss or skip this content.
- Keep it brief.
- Keep content contextual to the screen. This should not be a place to onboard the user to the entire app.
Best Match
On a search screen, if nothing exactly matches a user's query, content that contains the best match can be displayed by returning results for a query spelled slightly differently. By showing these results, the user may find what they're looking for.
<div className="ta-center m-x-auto" style={{width:420}}>
<img src={BookmarksBlue} width={105} height={94} className="m-b-3" />
<Headline>Sorry, we couldn't find any results for "<span className="c-blue">jfjkleikl</span>"</Headline>
<BodyText subdued>Remember to check your spelling or try searching for something else.</BodyText>
<div className="ta-left m-t-5">
<Headline size="small" className="m-b-2">Try these items instead</Headline>
<Card padding="thin">
<Card.Section>
<Stack spacing={2} alignItems="center">
<Stack.Item grow={0}><Thumbnail size="S" src="http://dummyimage.com/46" className="d-b" /></Stack.Item>
<Stack.Item grow={1}>
<Headline size="small" className="m-b-0">Item 1</Headline>
<BodyText size="small">Item Description</BodyText>
</Stack.Item>
<Stack.Item grow={0}><StatusLight color="success">25%</StatusLight></Stack.Item>
<Stack.Item grow={0}><Button size="small" content="Select" /></Stack.Item>
</Stack>
</Card.Section>
<Card.Section>
<Stack spacing={2} alignItems="center">
<Stack.Item grow={0}><Thumbnail size="S" src="http://dummyimage.com/46" className="d-b" /></Stack.Item>
<Stack.Item grow={1}>
<Headline size="small" className="m-b-0">Item 2</Headline>
<BodyText size="small">Item Description</BodyText>
</Stack.Item>
<Stack.Item grow={0}><StatusLight color="success">25%</StatusLight></Stack.Item>
<Stack.Item grow={0}><Button size="small" content="Select" /></Stack.Item>
</Stack>
</Card.Section>
<Card.Section>
<Stack spacing={2} alignItems="center">
<Stack.Item grow={0}><Thumbnail size="S" src="http://dummyimage.com/46" className="d-b" /></Stack.Item>
<Stack.Item grow={1}>
<Headline size="small" className="m-b-0">Item 3</Headline>
<BodyText size="small">Item Description</BodyText>
</Stack.Item>
<Stack.Item grow={0}><StatusLight color="success">25%</StatusLight></Stack.Item>
<Stack.Item grow={0}><Button size="small" content="Select" /></Stack.Item>
</Stack>
</Card.Section>
</Card>
</div>
</div>
Handling Empty States for Tables
Below are some best practice examples of handling empty states for tables.
First Time
A table with a first time empty state should not appear like a table. The table container can be replaced with a card containing the empty state. Any filters, tabs, and table headers should be hidden. Since the goal of a first time empty state is to show the user how to fill it, we should minimize cognitive load and direct their attention to one place.
A first time empty state for a table may also simply float on the page background instead of being contained in a card.
<Page
header={
<>
<Stack alignItems="center" spacing={2} wrap='wrap'>
<Stack.Item fill>
<Stack alignItems="center" spacing={1}>
<Headline size="large" className="m-b-0">Reports</Headline>
</Stack>
</Stack.Item>
<ButtonGroup>
<Button small primary>Create Report</Button>
</ButtonGroup>
</Stack>
<div className="m-t-4" style={{ background: '#DFE0E1', height: '1px'}} />
</>
}
>
<Card>
<div className="ta-center p-y-3 m-x-auto" style={{width:420}}>
<img src={Campaign} width={145} height={99} className="m-b-2" />
<Headline>Create Your First Report</Headline>
<BodyText subdued>Ready to build a great report? If you're not sure where to start, we'll show you the ropes. <Link primary>Learn More</Link></BodyText>
<Button primary outline className="m-t-3">Get Started</Button>
</div>
</Card>
</Page>
<Page
spacing='none'
maxWidth='wide'
header={
<div className="bg-white p-y-3" style={{ borderBottom: '1px solid #dfe0e1' }}>
<div className="m-x-auto p-x-5" style={{ maxWidth: '1280px' }}>
<Stack alignItems="center" spacing={2} wrap='wrap'>
<Stack.Item fill>
<Stack alignItems="center" spacing={1}>
<Headline size="large" className="m-b-0">Reports</Headline>
</Stack>
</Stack.Item>
<ButtonGroup>
<Button small primary>Create Report</Button>
</ButtonGroup>
</Stack>
</div>
</div>
}
>
<div className="m-x-auto p-b-3 p-x-5 p-y-2" style={{ maxWidth: '1280px' }}>
<div className="ta-center p-y-3 m-x-auto" style={{width:420}}>
<img src={Campaign} width={145} height={99} className="m-b-2" />
<Headline>Create Your First Report</Headline>
<BodyText subdued>Ready to build a great report? If you're not sure where to start, we'll show you the ropes. <Link primary>Learn More</Link></BodyText>
<Button primary outline className="m-t-3">Get Started</Button>
</div>
</div>
</Page>
Recurring
A table with a recurring empty state should show the table container, column header row with header names, and any filters. The row dividers should be removed and the content of the table should include only the empty state.
<Page
header={
<>
<Stack alignItems="center" spacing={2} wrap='wrap'>
<Stack.Item fill>
<Stack alignItems="center" spacing={1}>
<Headline size="large" className="m-b-0">Reports</Headline>
</Stack>
</Stack.Item>
<ButtonGroup>
<Button small primary>Create Report</Button>
</ButtonGroup>
</Stack>
<div className="m-t-4" style={{ background: '#DFE0E1', height: '1px'}} />
</>
}
>
<Table data={[]}>
<TableNoRecords>
<div className="ta-center m-x-auto p-y-6" style={{width:420}}>
<Icon name="money_off" size={32} className="m-b-2 c-neutral-80" />
<BodyText subdued size="small">You have no report history. When a report is complete, it will appear here. <Link primary>View active reports.</Link></BodyText>
</div>
</TableNoRecords>
<TableColumn field="Invoice #" />
<TableColumn field="Date" />
<TableColumn field="Description" />
<TableColumn field="Total" />
<TableColumn field="Paid" />
</Table>
</Page>