Usage Guidelines

Primary Page Actions

For the primary action on a screen, use a solid button filled with blue.

<ButtonGroup>
    <Button primary>Save Invoice</Button>
    <Button>Cancel</Button>
</ButtonGroup>

If the primary action on a screen is a destructive action, use negative color. Destructive actions should trigger a confirmation before the action is completed to be safe.

<ButtonGroup>
    <Button negative>Delete Invoice</Button>
    <Button>Cancel</Button>
</ButtonGroup>

Secondary Actions

When there is more than one action on the page that will surface information or start a workflow, outline buttons can be used for lower priority actions.

<ButtonGroup>
    <Button primary>Add Technician</Button>
    <Button primary outline>Add Contractor</Button>
</ButtonGroup>

A page can have primary and secondary negative actions.

<ButtonGroup>
    <Button negative>Remove Technician</Button>
    <Button negative outline>Remove Contractor</Button>
</ButtonGroup>

Neutral Actions

Default buttons are used for actions that don't have a positive or negative meaning

<Button>Copy Invoice Number</Button>

Default buttons are useful as tool bars.

<ButtonGroup attached>
    <Button>Filter</Button>
    <Button>Sort</Button>
    <Button>Refresh</Button>
</ButtonGroup>

Deemphasized & Repeated Actions

On data-heavy pages, like Card and Table based layouts, with significant amount of action buttons, Text buttons can be used so the page doesn't become overwhelming.

const Row = ({children}) => (
    <Stack alignItems="center" justifyContent="space-between" style={{
        borderTop: '1px solid #efefef',
        padding: '1em 0',
    }}>
        <div>{children}</div>
        <Button fill='subtle' primary>Edit</Button>
    </Stack>
);

render(
  <div>
    <Headline className="m-t-0 m-t-1">Employees</Headline>
    <Row>Lisbeth Anglin</Row>
    <Row>Etta Twiford</Row>
    <Row>Renea Finlayson</Row>
    <Row>Tomiko Lindblom</Row>
    <Row>Audria Vernon</Row>
  </div>
)

Button Alignment

Left Aligned Buttons

Left-aligned buttons are recommended for single page forms and focused tasks. The buttons are ordered from left to right by importance.

<Form>
    <Headline el="div" className="m-b-4">Add Contact</Headline>
    <Form.Group widths="equal">
        <Form.Input label="First Name" placeholder="Leia" />
        <Form.Input label="Last Name" placeholder="Organa" />
    </Form.Group>
    <Form.Select label="Home Planet" placeholder="Choose Planet" options={[
        {key:1, value: 1, text: 'Alderaan'},
        {key:2, value: 2, text: 'Bespin'},
        {key:3, value: 3, text: 'Coruscant'},
        {key:4, value: 4, text: 'Dagobah'},
        {key:5, value: 5, text: 'Hoth'},
        {key:6, value: 6, text: 'Kashyyyk'},
        {key:7, value: 7, text: 'Naboo',},
        {key:8, value: 8, text: 'Tatooine'},
        {key:9, value: 9, text: 'Yavin'},
    ]} />
    <Form.Group>
        <Form.Button primary>Save Contact</Form.Button>
        <Form.Button>Cancel</Form.Button>
    </Form.Group>
</Form>

Right Aligned Buttons

Buttons in page headers and footers prompt a user to move through a sequence of screens are right aligned to visually support navigation. The buttons are ordered from right to left by importance.

<Stack alignItems="center" justifyContent="space-between">
    <Headline size="small" className="m-0">Invoices</Headline>
    <ButtonGroup>
        <Button primary outline>Create Estimate</Button>
        <Button primary>Create Invoice</Button>
    </ButtonGroup>
</Stack>

Within Overlays, like Modals, actions are right-aligned as well to encourage forward progress through a workflow.

scaled: true
---
<div style={{ height: '200px' }}>
    <Modal
        open={true}
        footer={<ButtonGroup>
            <Button>Cancel</Button>
            <Button primary>Save Invoice</Button>
        </ButtonGroup>}
        portal={false}
    />
</div>

Centered Buttons

Centered buttons are used when the content is shown in a small, isolated view. These should be used sparingly and are most commonly within small Dialog windows and Modals.

frame: true
noPadding: true
---
<div style={{ height: '200px' }}>
    <Modal
        open={true}
        footer={<Button>Close</Button>}
        footerAlign="center"
        portal={false}
    />
</div>

Variations

Button Colors

There are 3 color options for buttons. Grey is the default and depending on the button action, can be changed to blue for primary actions or red for negative actions.

<div>
    <Button full primary>Primary Solid</Button><br/>
    <Button full>Default Solid</Button><br/>
    <Button full negative>Negative Solid</Button><br/>
</div>
<div>
    <Button full outline primary>Primary Outline</Button><br/>
    <Button full outline>Default Outline</Button><br/>
    <Button full outline negative>Negative Outline</Button>
</div>
<div>
    <Button full fill='subtle' primary>Primary Text</Button><br/>
    <Button full fill='subtle'>Default Text</Button><br/>
    <Button full fill='subtle' negative>Negative Text</Button><br/>
</div>

Button Fills

There are three fills a button can have. A solid fill is useful for bold and important actions. An outline fill can be used for secondary actions and looks good next to a solid button and stand out on colored backgrounds. A text button is useful for actions that we don't need to call a lot of attention to.

<div>
    <Button full>Solid Button</Button>
    <br/>
    <Button full outline>Outlined Button</Button>
    <br/>
    <Button full fill='subtle'>Text Button</Button>
</div>

Disabled Button

We have two separate ways of disabling buttons. A disabled attribute will prevent clicks and change the button to a grey style. An inactive attribute will prevent clicks but keeps the button looking the same. This is useful for preventing stray clicks while an API call is running or showing an outlined-to-active state change.

<div>
    <Button disabled>Disabled Button</Button>
    <br/><br/>
    <Button inactive>Unclickable Button</Button>
</div>

Button Sizes

We support three sizes of buttons that can be set using the size prop. Small buttons are useful for secondary or ancillary actions. Large buttons are great for important call-to-actions and helping unstick a user in a setup flow.

<div>
    <Button xsmall>X-Small Button</Button>
    <br/><br/>
    <Button small>Small Button</Button>
    <br/><br/>
    <Button>Normal Button</Button>
    <br/><br/>
    <Button large>Large Call-to-Action Button</Button>
</div>

Button Widths

The default width of buttons has a consistent amount of padding between the text and the ends of the button. This can be overridden with the width property, either setting it to a specific size or making the button full width. Specific sized buttons should only be used when buttons are next to each other or in a column and have variable text lengths. Keeping them the same width will make the buttons feel intentional. Setting a width for every button is not recommended.

<div>
    <Button>Fluid Width Button</Button>
    <br/><br/>
    <Button width="300px">Specific Width Button</Button>
    <br/><br/>
    <Button full>Full Width Button</Button>
</div>

Buttons with Icon

Buttons can have an icon to the left or right of the action label.

<ButtonGroup>
    <Button iconName="add">Add new item</Button>
    <Button iconName="expand_more" iconPosition="right">Menu</Button>
    <Button icon={<span>&trade;</span>} iconPosition="right">Custom Icon</Button>
</ButtonGroup>

Button Icons

When pairing an Icon and an action, an Icon-only Button is used to control the interaction. To add clarity to the action, Button Icons should be paired with Tooltips.

<ButtonGroup>
    <Tooltip el="div" text="Add New Widget"><Button iconName="add"/></Tooltip>
    <Tooltip el="div" text="Edit Invoice"><Button iconName="edit"/></Tooltip>
    <Tooltip el="div" text="Check Availability" direction="b"><Button iconName="event" /></Tooltip>
    <Tooltip el="div" text="More Actions" direction="t"><Button iconName="more_vert" /></Tooltip>
</ButtonGroup>
<Form>
    <Stack spacing="1">
        <Tooltip el="div" text="Remove Widgets"><Button iconName="remove"/></Tooltip>
        <Input style={{width: '50px'}} defaultValue="5" />
        <Tooltip el="div" text="Add More Widgets" direction="t"><Button iconName="add" primary /></Tooltip>
    </Stack>
    <Stack spacing="1" className="m-t-3">
        <Tooltip el="div" text="Remove Widgets"><Button small iconName="remove"/></Tooltip>
        <Input small style={{width: '50px'}} defaultValue="5" />
        <Tooltip el="div" text="Add More Widgets" direction="t"><Button small iconName="add" primary /></Tooltip>
    </Stack>
</Form>
state: { value: 1 }
---
const ButtonIconExample = () => {
    const options = [
        {key:1, value: 1, text: 'Australia'},
    ];
    return (
        <Form>
            <Stack spacing="1">
                <Select options={options} value={1} />
                <Tooltip el="div" text="Confirm" direction="b"><Button iconName="check" primary/></Tooltip>
                <Tooltip el="div" text="Cancel" direction="bl"><Button iconName="close"/></Tooltip>
            </Stack>

            <Stack spacing="1" className="m-t-3">
                <Select options={options} small value={1} />
                <Tooltip el="div" text="Confirm" direction="b"><Button small iconName="check" primary/></Tooltip>
                <Tooltip el="div" text="Cancel" direction="bl"><Button small iconName="close"/></Tooltip>
            </Stack>
        </Form>
    )
}
render(ButtonIconExample)

Loading Button

Add the loading prop to the button and it disables and gives a loading animation. Useful for preventing double submissions on forms. The button width will not change.

<div>
    <Button primary loading>Button</Button>
    <br/><br/>
    <Button outline primary loading>Button</Button>
    <br/><br/>
    <Button fill='subtle' primary loading>Button</Button>
</div>
const LoadingButton = (props) => {
    const [loading, setLoading] = React.useState(false);

    const onClickHandler = () => {
        setLoading(true);
        setTimeout(function() { setLoading(false); }, 2000);
    }

    return (
        <Button onClick={onClickHandler} loading={loading} {...props} />
    )
}

render (
    <div>
        <LoadingButton primary>Click Me</LoadingButton>
        <br/><br/>
        <LoadingButton primary>A Longer Example</LoadingButton>
        <br/><br/>
        <LoadingButton primary full>A Really Long Example</LoadingButton>
    </div>
)

Technical Examples

Click Action

Use the onClick prop to pass a function to the button.

var ClickFunc = function() {
    alert('Clicked!');
}
render (
    <Button onClick={ClickFunc}>Button</Button>
)

Linked Button

The standard button component uses a span element because most buttons will be passed a function. If you pass the button a href prop, it will become an a element and click through to the url.

<Button href="//servicetitan.com">Link Button</Button>

You can pass Button through the trigger prop of the Dropdown.

<Dropdown
    trigger={<Button small iconName="expand_more" iconPosition="right">Use the force</Button>}
    icon={null}
>
    <Dropdown.Menu>
        <Dropdown.Item text="Precognition" />
        <Dropdown.Item text="Psychometry" />
        <Dropdown.Item text="Telepathy" />
        <Dropdown.Item text="Shadow Vision" />
        <Dropdown.Item text="Levitation" />
    </Dropdown.Menu>
</Dropdown>

Best Practices

  • Use the same button sizes within an action area
  • Prioritize the most important actions. Too many calls to action can cause confusion and make users unsure of what to do next.

Related Components

  • For a text button inline in a paragraph, use a Link.
  • To group Buttons together, use a Button Group.

Importing

import { Button } from '@servicetitan/design-system';