Button
Trigger an action or event such as submitting a form, opening a dialog or making a choice.
To set a button's appearance, use the appearance
prop:
<DocsBox css={{ backgroundColor: "$grey1", padding: "$lg" }}> <Stack direction="horizontal" wrap="wrap"> <Button appearance="primary">Primary</Button> <Button>Standard</Button> <Button appearance="onSurface">On Surface</Button> <Button appearance="ghost">Ghost</Button> <Button appearance="link">Link</Button> </Stack> </DocsBox>
Unless it is considered to be a primary action on a page, use a standard/default button.
Should I use a primary or standard button? Consider the context of where the button is being used and whether this button's action is the "core" action the use should perform (or simply an option to take).
<Button>Action</Button>
Use this for primary form actions, such as “save” or “update”. Ideally there should only be one primary action on a page, and definitely only one in a single form.
When there is a clear action the user is expected to perform in any given context, use the Primary action button. There should only be one primary action.
<Button appearance="primary">Primary Action</Button>
In situations where you want to use a standard button on the vitality surface background color, you can use the onSurface variant. This will change the background color of the button 1 step darker to better contrast against the background
<DocsBox css={{ backgroundColor: "$neutral12", padding: "$lg", width: "100%", }} > <DocsBox css={{ backgroundColor: "$neutral2", padding: "$lg", width: "100%", }} > <Stack direction="horizontal"> <Button appearance="onSurface">Action used on Surface Colour</Button> <Button>Do not use Standard on surface</Button> </Stack> </DocsBox> </DocsBox>
As another form of primary action, use destructive buttons to suggest the high severity of an action. These should be used sparingly – in cases like deleting an un-recoverable entity or any data which will be gone forever.
<Button appearance="destructive">Delete Patient</Button>
As another form of primary action, use warning buttons to suggest the moderate severity of the action. These should be used sparingly – in cases like archiving, clearing or removing a recoverable entity or any data which will be hidden from easy access after the action is performed.
<Button appearance="warning">Clear Settings</Button>
Ghost buttons have a transparent background and utilise the primary text colour.
<Button appearance="ghost">Clear Settings</Button>
Link buttons take on the appearance of a link including underline when hovered.
<Button appearance="link">Clear Settings</Button>
Use action verbs or phrases to tell the user what will happen next.
- Icon: Use an icon to convey more meaning.
- Label: Text that indicates the action that will be performed when selecting the button.
Although the default size should be used predominantly, a compact
size is also available. Use this size intentionally when you need to save space or inside tables.
<Stack direction="horizontal"> <Button appearance="primary" size="compact"> Compact </Button> <Button appearance="primary">Default</Button> </Stack>
Buttons can be expanded to full width to fit their parent container.
<Button shouldFitContainer appearance="primary"> Full width Button </Button>
A button should appear disabled when its action cannot be performed. For example:
- Form Completion: A ‘Submit’ button remains disabled until all mandatory fields are filled out.
- Form Updates: An ‘Apply Changes’ or 'Save' button is disabled until a form is altered.
- Sequential Actions: If actions must be performed in sequence, disable buttons for later steps until the current step is complete.
- Permissions A button should be disabled if the user does not have the necessary permissions or access rights.
- Display a button as disabled when there is a clearly defined action or condition that the user has control over to allow the process
- Add the
required
property for any FormFields that are required to be complete before enabling buttons
() => { const [value, setValue] = React.useState(""); return ( <Stack align="end"> <FormField label="First Name" required value={value} onChange={(e) => { setValue(e.target.value); }} helperMessage="This Field is required to continue" /> <Button appearance="primary" disabled={!value} tooltipContent={!value ? "Provide first name to continue" : null} > Continue </Button> </Stack> ); };
- However when there are multiple actions with dependencies beside each other it's best to keep the buttons enabled and provide feeback in the form of toast notifications or callouts to specifiy why the action didn't follow through
() => { const [error, setError] = React.useState(""); return ( <Box width="100%"> <Stack align="end"> {error && ( <Callout severity="critical" title="Something went wrong" description={`You cannot ${error} because this is a demo`} /> )} <Stack direction="horizontal"> <Button onClick={() => setError("Preview")}>Preview</Button> <Button onClick={() => setError("Print")}>Print</Button> <Button onClick={() => setError("Save")} appearance="primary"> Save </Button> </Stack> </Stack> </Box> ); };
Including a tooltip for a disabled button is required. It provides clarity to users about why the button is disabled and helps manage their expectations. Add a message in in a tooltip that explains the reason for the button’s disabled state. For example:
“Insufficient permissions”
This way, users will understand why they can’t interact with the button and what action they need to take to enable it.
<DocsBox css={{ backgroundColor: "$grey1", padding: "$lg" }}> <Stack direction="horizontal"> <Tooltip content="Insufficient permissions"> <Button disabled>Edit Quote</Button> </Tooltip> <Button>Edit Quote</Button> </Stack> </DocsBox>
You can show a Spinner as an overlay on the button when you set an isLoading
prop to true
.
The component adds a spinner with the correct size and color based on the size
and appearance
props passed to the button.
() => { const [isLoading, setIsLoading] = React.useState(); return ( <Stack> <Typography variant="sectionTitle">Loading Example</Typography> <Stack direction="horizontal"> <Button isLoading={isLoading} onClick={() => setIsLoading(true)}> Cancel </Button> <Button appearance="primary" isLoading={isLoading} onClick={() => setIsLoading(true)} > Save Changes </Button> <Button appearance="primary" size="compact" isLoading={isLoading} onClick={() => setIsLoading(true)} > Save Changes </Button> </Stack> <Typography variant="caption"> Note: in reality, only one button would be set to loading at any time </Typography> <Checkbox onChange={() => setIsLoading(!isLoading)} checked={isLoading} value={isLoading} label="isLoading" name="isLoading" id="isLoading" /> </Stack> ); };
Use an icon to convey meaning quicker. Buttons can include an icon before or after the text.
<Button appearance="primary" iconLeft={<Medications />}> Add </Button>
<Button appearance="primary" iconRight={<Request />}> New Request </Button>
Do not include both left and right icons - choose one.
<DocsBox css={{ display: "flex", flexDirection: "column", backgroundColor: "$grey1", padding: "$lg", gap: "$md", width: "100%", boxShadow: "$sm", borderRadius: "$default", }} > <Stack direction="horizontal" justify="between" wrap="wrap" gap="sm"> <Typography variant="pageTitle">Example</Typography> <Stack direction="horizontal"> <Button>Wrap-up</Button> <Button iconLeft={<Pdf />}>Print</Button> <Button appearance="primary" iconLeft={<Add />}> Add </Button> </Stack> </Stack> <Typography> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam vulputate eros arcu, a vehicula urna sagittis in. Duis libero justo, vehicula at dui a, luctus maximus elit. Nulla quis orci vel diam placerat porta et sit amet nunc.{" "} </Typography> <Stack direction="horizontal" align="center" justify="end"> <Typography variant="caption">Was this page helpful?</Typography> <Button size="compact">No</Button> <Button size="compact">Yes</Button> </Stack> </DocsBox>
<DocsFlex spacing="lg" direction="column" css={{ backgroundColor: "$grey1", padding: "$lg", minWidth: 250, boxShadow: "$sm", borderRadius: "$default", }} > <Typography variant="sectionTitle"> Permanently delete this patient? </Typography> <Typography>Please be aware that this action is irreversible.</Typography> <Stack direction="horizontal" justify="end"> <Button>Cancel</Button> <Button appearance="destructive">Yes, Delete</Button> </Stack> </DocsFlex>
Description
The visual appearance of the component.
Type
"primary" | "warning" | "link" | "onSurface" | "ghost" | "standard" | "destructive"
Default Value
standard
Description
Text contents of the component.
Type
ReactNode
Description
The Icon to the left of the Button text.
Type
ReactNode
Description
The Icon to the right of the Button text.
Type
ReactNode
Description
Show a spinner as an overlay on the button when an asynchronous process is loading. Disables the button whilst true
Type
(boolean | "true"
Type
boolean
Description
The size of the button
Type
"default" | "compact"
Default Value
default