Buttons guidelines

Allow people to take action, make choices, and move forward.

CTA Button

Maturity

RC

FYQ2 target

♼ Care

Figma component

Repository

Storybook

Action Button

Maturity

RC

FYQ2 target

♼ Care

Figma component

Repository

Storybook

Related content


Overview

The previous version of our Buttons was plagued with inconsistencies due to a lack of definition and maintenance, which cascaded badly in the code.

Benefits

  1. 1:1 parity design/development.
  2. Simplified properties and usage
    1. On the design side, we simplified the rules and styling, all available via semantic tokens.
    2. On the code side, we removed properties that should belong to the parent container, hardcoded values, and magic numbers.
  3. Better accessibility, with holistic interaction states, colors, and more.

How to migrate

containerStyle

The prop containerStyle has been removed and no longer needed.

ctype

The ctype prop has been removed. It has been replaced by two separate buttons, CTAButton and ActionButton, as well as the emphasis prop.

In most cases there is a direct translation between the previous ctype and the new buttons.

Before

After

bordered

<ActionButton>

borderedMuted

<ActionButton>

danger

<CTAButton destructive>

flatBlue

<ActionButton>

flatGrey

<ActionButton>

floating

<CTAButton>

golden

<CTAButton>

but there are some situations to take into account.

If a Button is a companion to another Button that should be a CTAButton, use emphasis="tertiary".


                                                        
                                                        
                                                            // Before
                                                        <Flex gap="16px">
                                                          <Button size="m" ctype="bordered" onClick={handleCancel}>
                                                            Cancel
                                                          </Button>
                                                          <Button size="m" onClick={handleDelete}>
                                                            Delete
                                                          </Button>
                                                        </Flex>
                                                        
                                                            

                                                        
                                                        
                                                            // After
                                                        <Flex gap="16px">
                                                          <CTAButton destructive size="MD" onClick={handleDelete}>
                                                            Delete
                                                          </CTAButton>
                                                          <CTAButton size="MD" emphasis="tertiary" onClick={handleCancel}>
                                                            Cancel
                                                          </CTAButton>
                                                        </Flex>
                                                        Note that this example also changes the arrangement of the buttons.
                                                        
                                                            

If a Button is supposed to be a ActionButton but there is a need for less emphasis, like a Menu Button, use emphasis="tertiary".

When migrating a Button to an ActionButton, make sure to add a related icon as well.

For more information see our Button Guidelines documentation.

disabledTip

The disabledTip prop has been removed as Tooltips should be used to clarify the functionality of a button and not to describe why something is disabled or has an error. Instead use a

loading

The loading prop has renamed to waiting as it better describes what is occurring.

In some cases the button might be waiting for an action to finish like deleting or moving something. And loading implies data transfer.

There is also no need to disable a button when it’s in it’s waiting state, as this is handle automatically.

In addition a button in waiting state will add a spinner and update the accessible label to be Waiting for {action}, so the label can be left alone as well.


                                                        
                                                        
                                                            // Before
                                                        <Button
                                                          disabled={isLoading}
                                                          loading={isLoading}
                                                          onClick={onConfirm}
                                                          ctype="danger"
                                                        >
                                                          {isLoading ? 'Deleting...' : 'Delete'}
                                                        </Button>
                                                        
                                                            

                                                        
                                                        
                                                            // After
                                                        <CTAButton
                                                          waiting={isLoading}
                                                          onClick={onConfirm}
                                                        	destructive
                                                        >
                                                          Delete
                                                        </CTAButton>
                                                        
                                                            

iconPosition

The prop iconPosition has been removed as icons are always consistently at the start of ActionButton.

marginmymxmtmrmbml, etc.

Margin related props have been removed. Either migrate to wrapping with a Flex or Box with the related margin props or move to using a Flex with gap.

onMouseEnteronMouseLeave, etc

Instead of using onMouse* even handlers, use the equivalent onPointer* event handler instead. As pointer events handle all different input types (touch, pen, mouse, etc).


                                                        
                                                        
                                                            // Before
                                                        <Button onMouseEnter={handleMouseEnter}>New project</Button>
                                                        
                                                            

                                                        
                                                        
                                                            // Before
                                                        <ActionButton onPointerEnter={handleMouseEnter}>New project</ActionButton>
                                                        
                                                            

paddingpypxptprpbpl, etc.

Padding related props have been removed. In most cases you shouldn’t need to change the padding of the new buttons. If you do happen to run into a case where you would need to, let us know.

size

The size prop has had it’s value updated to have a consistent naming pattern of t-shirt sizes.

Before

After

sm

SM

m

MD

lg

MD


                                                        
                                                        
                                                            // Before
                                                        <Button
                                                          size="m"
                                                          onClick={createMazeHandler}
                                                        >
                                                          New maze
                                                        </Button>
                                                        
                                                            

                                                        
                                                        
                                                            // After
                                                        <CTAButton
                                                          size="MD"
                                                          onClick={createMazeHandler}
                                                        >
                                                          New maze
                                                        </CTAButton>
                                                        
                                                            

Arrangement

For complementary buttons, make sure to follow the F pattern.


                                                        
                                                        
                                                            // Before
                                                        <Flex gap="16px">
                                                          <Button size="m" ctype="bordered" onClick={handleCancel}>
                                                            Cancel
                                                          </Button>
                                                          <Button size="m" onClick={handleDelete}>
                                                            Delete
                                                          </Button>
                                                        </Flex>
                                                        
                                                            

                                                        
                                                        
                                                            // After
                                                        <Flex gap="16px">
                                                        	<CTAButton destructive size="MD" onClick={handleDelete}>
                                                            Delete
                                                          </CTAButton>
                                                          <CTAButton size="MD" emphasis="tertiary" onClick={handleCancel}>
                                                            Cancel
                                                          </CTAButton>
                                                        </Flex>
                                                        
                                                            

For more information, see our documentation on Button arrangement.

Destructive Actions

If the Button is triggering a destructive action, be sure to add the destructive prop to it.


                                                        
                                                        
                                                            // Before
                                                        <Button onClick={handleDelete}>
                                                          Delete
                                                        </Button>
                                                        
                                                            

                                                        
                                                        
                                                            // After
                                                        <CTAButton destructive onClick={handleDelete}>
                                                          Delete
                                                        </CTAButton>
                                                        
                                                            

Icon Buttons

Previously we were building ad-hoc solutions for Icon Only buttons, but now this is built directly into ActionButton.

Make sure to add the iconOnly prop as well as give the ActionButton an accessible label.


                                                        
                                                        
                                                            // Before
                                                        const IconButton = styled.button`
                                                          cursor: pointer;
                                                          border: none;
                                                          width: 40px;
                                                          height: 40px;
                                                          display: flex;
                                                          align-items: center;
                                                          justify-content: center;
                                                          border-radius: 4px;
                                                          background-color: transparent;
                                                          &:hover {
                                                            background-color: ${colors.neutral100};
                                                            color: ${colors.red500};
                                                          }
                                                          & ${Icon} {
                                                            &:hover {
                                                              color: ${colors.red500};
                                                            }
                                                          }
                                                        `;
                                                        
                                                        <IconButton onClick={onButtonClick}>
                                                          <Icon name="trash-can" fontSize="24px" color={colors.neutral500} />
                                                        </IconButton>
                                                        
                                                            

                                                        
                                                        
                                                            // After
                                                        
                                                        <ActionButton icon='trash-can' iconOnly onClick={onButtonClick}>
                                                          Delete
                                                        </ActionButton>
                                                        
                                                            

Note that in this example Delete will act as an accessible label and not visually show because off the iconOnly prop.

Real Word Examples

TextSection


                                                        
                                                        
                                                            // Before
                                                        <Flex mt="18px" alignItems="center" justifyContent="flex-end">
                                                          <Box mr="16px">
                                                            <Button size="m" ctype="bordered" onClick={() => setShowDeleteModal(false)}>
                                                              Cancel
                                                            </Button>
                                                          </Box>
                                                          <Button size="m" onClick={handleDelete} data-e2e="delete-text-section-button">
                                                            Delete
                                                          </Button>
                                                        </Flex>
                                                        
                                                            

                                                        
                                                        
                                                            // After
                                                        <Flex mt="18px" gap="16px" alignItems="center" justifyContent="flex-end">
                                                          <CTAButton emphasis="tertiary" size="MD" onClick={() => setShowDeleteModal(false)}>
                                                            Cancel
                                                          </CTAButton>
                                                          <CTAButton destructive size="MD" onClick={handleDelete} data-e2e="delete-text-section-button">
                                                            Delete
                                                          </CTAButton>
                                                        </Flex>
                                                        
                                                            

DeleteButton


                                                        
                                                        
                                                            // Before
                                                        const IconButton = styled.button`
                                                          cursor: pointer;
                                                          border: none;
                                                          width: 40px;
                                                          height: 40px;
                                                          display: flex;
                                                          align-items: center;
                                                          justify-content: center;
                                                          border-radius: 4px;
                                                          background-color: transparent;
                                                          &:hover {
                                                            background-color: ${colors.neutral100};
                                                            color: ${colors.red500};
                                                          }
                                                          & ${Icon} {
                                                            &:hover {
                                                              color: ${colors.red500};
                                                            }
                                                          }
                                                        `;
                                                        
                                                        <IconButton onClick={onButtonClick}>
                                                          <Icon name="trash-can" fontSize="24px" color={colors.neutral500} />
                                                        </IconButton>
                                                        
                                                            

                                                        
                                                        
                                                            // After
                                                        
                                                        <ActionButton icon='trash-can' iconOnly onClick={onButtonClick}>
                                                          Delete
                                                        </ActionButton>
                                                        
                                                            

Let Us Know

For cases where you are not easily able to migrate Button to CTAButton/ActionButton or Text is missing a property you need, let us know in #design-system.