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.

<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>
<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>
<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>

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>
<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>

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.
title: Illustration + Headline + Explanation
---
<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>
title: Illustration + Headline + Explanation + CTA
---
<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.
title: Illustration + Headline + Explanation + CTA
---
<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>
title: Illustration + Headline + Description + Extra Info + CTA
---
<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.
title: Description only
---
<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>
title: Icon + Description + In-line CTA
---
<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.
title: Icon + Description with Instructions
---
<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>
title: Icon + Description + In-line CTA
---
<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.
title: Icon + Description
---
<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>
title: Illustration + Description + In-line CTA
---
<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.
title: Illustration + Headline + Description with Explanation
---
<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>
title: Icon + Description with Explanation
---
<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.
title: Illustration + Headline + Description with Explanation + CTAs
---
<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>
title: Icon + Description with Explanation
---
<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 = ({active, ...props}) => (
    <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.

title: As 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>
title: Floating
---
<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>