Getting Started

When writing an error or warning message, consider these questions:

  • What is the issue?
    • Knowing what the issue is (or knowing that we don't know) can help frame what to communicate to the user.
  • What is the cause of the issue?
    • Common reasons could be user action, server/network issues, or not being able to find a resource.
  • What can the user do to resolve the issue?
    • If it's the app fault, explain that. If it's user error, can you identify the most likely cause?
  • Is there a path a user can take to resolve the issue?
    • Whenever it is possible for a user to take action on the issue, a path should be given. For example, if using a Banner or Toast, provide a call to action in them.
    <Toast
        title="Unable to export Batch #12345"
        portal={false}
        duration={0}
        onPrimaryActionClick={() => {}}
        primaryActionName={"Fix Batch Issue"}
        status="critical"
    >
        We have encountered issues with exporting Batch #12345. To complete the export, please fix the issues.
    </Toast>

Quick Use Cases

Each of these is explained in more detail. For needing a component quickly, consider these common scenarios.

Use CaseComponent(s) to use
Page level error or warning has occurredBanner
Form validation errorsInline Error Text inside a Form, a Banner as a summary
Background process problemToast
No resultsEmpty State
Server/Network errorEmpty State or Toast
Application wide error or warningAnnouncement

Types of Errors and Warnings

Page-level Messages

This error type is used when an error applies to the entire page. They are represented as Banners, placed at the bottom of the Page Header.

span: 12
---(
    <Banner status="critical" title="There are problems with the new rule">
        Please specify a timing for the email before proceeding.
    </Banner>
)
span: 12
---(
    <Banner
        status="warning"
        title="Individuals receive custom-filtered scheduled reports based on this report."
    >
        Removing columns with employee names removes these filters.
    </Banner>
)
span: 12
---(
    <Banner
    status="warning"
    title="Welcome to your Widget onboarding period"
            onPrimaryActionClick={() => {}}
        primaryActionName={"Setup Campaign"}
            onSecondaryActionClick={() => {}}
        secondaryActionName={"Read More"}
    >
        You are currently in onboarding mode. You are limited to 500 widgets per day. If your campaign is greater than 500 widgets today, then we will defer the remainder until tomorrow. Based on your data, we recommended sending your <Link>Widget X</Link> and <Link>Widget Y</Link> campaigns at this time.
    </Banner>
)

They can be used to:

  • Summarize individual errors found on the rest of the page.
  • Inform the user of important, but non-critical information about the page.

Form Errors and Validation

Form errors are among the most common type of errors. Each individual component page provides specific styling and text location. It is recommended to also use a Banner as a summary when multiple errors exist.

Validating on submit

This validation occurs after a user has hit a save or submit button. These errors are paired with Banners and individual form field errors.

---(
    <Form>
        <Form.Group widths="equal" className="m-b-0">
            <Form.Input error label="Hours" value="3" />
            <BodyText
                subdued
                className="m-b-2"
                style={{ alignSelf: "flex-end" }}
            >
                to
            </BodyText>
            <Form.Input error label=" " value="1" />
        </Form.Group>
        <Form.Field error="Maximum hours must be greater than the minimum." />

        <Form.Group widths="equal" className="m-b-0">
            <Form.Input label="Price" value="2.00" shortLabel="$" />
            <BodyText
                subdued
                style={{ alignSelf: "center" }}
            >
                to
            </BodyText>
            <Form.Input
                error
                label=" "
                value="-4.50"
                shortLabel="$"
                error="Value cannot be negative"
            />
        </Form.Group>
    </Form>
)

Validating before submission

When format requirements exist for a field (such as the @ in an email input), validating the form element after a user has left focus can help resolve errors.

When to use validation before submission:

  • When an Input has known formatting requirements. If the requirement is ambiguous to a user (e.g. password requirements), add a field description.

  • In the initial user interaction, validate only after a user has left focus on the field and if the user entered anything.

  • When a user interacts with an errored field, validate after each keystroke. This helps the user identify when the user has met the field requirements.

When to avoid validation before submission:

  • While the user is still interacting with the field.
  • When a field was left empty by the user.
  • When it takes at least a second for the codebase to validate the field.

It is recommended to add a Banner at the top of a form that has errors. If the form is the main content of the page, it follows the Page-level guidelines. Otherwise, it appears wherever the top of the form is.

  • The Banner should only appear after a validating on submit. Validations before submission do not need a Banner.

  • The summary should list out each of the errors encountered on the page.

  • In general, the summary should not be used alone. Inline help should be added when possible.

---(
    <Card>
        <Banner status="critical" title="We're unable to submit the Timesheet" className="m-b-4">
            <ul className="p-t-1-i">
                <li>A job must be selected.</li>
                <li>Arrived time cannot be before 7:00 AM </li>
                <li>Done date cannot be before arrived date. </li>
            </ul>
        </Banner>
    <Form>
        <Form.AnvilSelect trigger={{placeholder: 'Select a Job'}} label="Job #" error="A job must be selected." options={[]} />
        <Form.Group widths="equal">
            <Form.Input label="Arrived Time" value="01/01/2020" />
            <Form.Input error="Arrived time cannot be before 7:00 AM." label=" " value="5:15 AM" />
        </Form.Group>
        <Form.Group widths="equal" className="m-b-0">
            <Form.Input label="Done Time" value="12/31/2019" error="Done date cannot be before arrived date." />
            <Form.Input label=" " value="11:00 AM" />
        </Form.Group>
    </Form>
    <Card.Section>
        <ButtonGroup className="justify-content-end">
            <Button>Cancel</Button>
            <Button primary >Submit Timesheet</Button>
        </ButtonGroup>

    </Card.Section>
    </Card>
)

System and Network Errors

System errors can typically be described as 400 or 500 type errors. If there is a place for it on the page, it is preferred to integrate an Empty State into the section. Otherwise, using a Toast is preferred over components such as the Banner or Announcement.

  • When a system error is the apps fault, take responsibility.

  • If there is an HTTP response, place it at the end of the body content.

  • When using the Toast to present an error, it should persist on the page.

  • When it is possible to determine the solution, provide it to the user. For example, a 401 error resulting from not being logged in.

Application Errors and Warnings

App-level messages are used to convey a status relevant to the entire experience, represented with an Announcement. These are not used in specific products within the platform. Some examples might include a sandbox environment message and a scheduled downtime notice.

<Announcement
        status="warning"
        title="You have no credit card specified. Please add it before your service is suspended in 3 days."
        onClose={() => {}}
        actionName="Add Credit Card"
        onActionClick={() => {}}
    />

Empty State Errors and Warnings

Many different contexts for an empty state can exist, some of which can be tied to errors and warnings. See the Empty States pattern page for all variations. Sections relevant to errors include: workflows inhibited by the empty state, parsing, and server errors

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

Errors vs Warnings

Anvil provides the option of warning and error statuses across many of its components. Warnings, usually represented in yellow or orange, are a way of providing a less severe notification to users. They are useful when users should be informed of something, but aren’t necessarily required to take action on something.

Examples where warnings are preferred

  • If a user can correct the issue at a later point
  • The system detects something might be wrong from a user input
  • To signal that significant change may/will happen in the future
  • To prevent future errors from occuring.

Examples where errors are preferred

  • If a user cannot proceed in a task without resolving the issue
  • When server or network issues arise
  • For form validation

Preventive Measures

While we can’t prevent all errors, we can design interfaces that help minimize user mistakes.

  • For simple layouts, the primary action can be disabled until all required fields are filled out, and paired with a Tooltip to give the a user a hint. In complex layouts however, a submit-type button can help a user figure out what to do to proceed.
---
const Example = () => {
    return (
        <Takeover.Footer>
            <ButtonGroup className="row-reverse">
                <Button>Previous</Button>
                <Tooltip
                    text="Fill out all the fields in the form to proceed."
                    el="div"
                    direction="tl"
                    portal
                >
                    <Button primary disabled>
                        Next
                    </Button>
                </Tooltip>
            </ButtonGroup>
        </Takeover.Footer>
    )
}
render (<Example />)
  • Adding a Dialog if a user is about to leave the page before saving. While this may not produce a tangible UI error, this helps a user avoid mistakes.
frame: true
---(
    <div style={{ height: "230px" }}>
        <Dialog
            open={true}
            title="Save for later?"
            portal={false}
            onPrimaryActionClick={() => {}}
            primaryActionName="Save"
            onSecondaryActionClick={() => {}}
            secondaryActionName="Cancel"
        >
            You can always set up this campaign at a later time.
        </Dialog>
    </div>
)
frame: true
---(
    <div style={{ height: "230px" }}>
        <Dialog
            open={true}
            title="Delete Email?"
            portal={false}
            onPrimaryActionClick={() => {}}
            primaryActionName="Delete"
            onSecondaryActionClick={() => {}}
            secondaryActionName="Cancel"
            negative
        >
            Are you sure you want to delete this email and it scheduling
            interval?
        </Dialog>
    </div>
)
  • When form field elements are required, the * can help users identify what they need to fill out. Alternatively, when most fields are required, you can mark particular ones as optional.
span: 6
---(
    <Form>
        <Form.Input
            label="Full Name"
            labelProps={{
                required: true,
            }}
        />
        <Form.Input label="Street Address" />
    </Form>
)
span: 6
---(
    <Form>
        <Form.Input label="Sender Name" />
        <Form.TextArea
            label="Legal Copy"
            labelProps={{
                optional: true,
            }}
            placeholder="Placeholder Text"
        />
    </Form>
)
  • When possible, constrain controls to only accept valid values. For example, if a field only accepts numbers, prevent a user from entering letters.

Anti-Patterns

Some components could theoretically be used to display errors, but should be avoided.

  • Don’t use Modals, Dialogs, or browser alerts to display errors or warnings Unless the content already existed in these overlays, these components should not be used to display errors. These components interrupt, adding an extra step to resolve errors.
frame: true
---(
    <div style={{ height: "280px" }}>
        <Dialog
            open={true}
            title="There were errors with the submission"
            portal={false}
            onPrimaryActionClick={() => {}}
            primaryActionName="Ok"
        >
        <ul className="m-b-0 p-l-3">
            <li>Password must be at least 8 characters.</li>
            <li>Submitted password was used in the last 6 months.</li>
            </ul>
        </Dialog>
    </div>
)
status: critical
title: Poor Error - A Banner should be used over a Dialog for summaries
---
  • Avoid overlay components to display error messages when an inline variation exists. Tooltips and Popovers can prevent an end user from scanning the content of a page.

  • Don’t validate form elements while a user is still interacting with it. Many form elements do not start off validated correctly (e.g. typing out an email at the start will be missing the @).

  • Avoid Red Buttons to indicate an error. Red buttons signify that an act is destructive (such as deleting a document or an action that cannot be undone). Other components should be used to signify the presence of an error.

Copy Guidelines

  • Content should be clear and easy to understand. It should be encouraging without being overly apologetic or humorous.

  • Avoid development jargon. Users are unlikely to be familiar with the inner workings of the app or web development. Frame copy toward user actions and goals, not the underlying software cause of the problem.

  • If it's known how to resolve the issue, the copy should explain it. For example, "Enter a maximum price higher than the minimum price." is more helpful than "Enter a valid maximum price".

  • When user action caused the error, avoid outright blame on them.

  • When the error is caused by the app, accept responsibility and apologize.

  • Headings should be sentence case. Body text should use full sentences with punctuation.

External Resources