Buttons allow users to perform actions within a surface. They can be used alone for immediate action, or as a trigger for another component, like Dropdown or Popover.

also known as Action, CTA

Figma:

Web:

Android:

A11y:

Props

Component props
Name
Type
Default
text
Required
string
-

Text to render inside the Button to convey the function and purpose of the Button.

accessibilityControls
string
-

A unique id indicating the element or elements whose contents or visibility are controlled by Button. See the Accessibility guidelines to learn more.

accessibilityExpanded
boolean
-

Needed if Button controls the visibility of other elements, e.g. Dropdown or Flyout. This is used to indicate if the controlled grouping is currently expanded or collapsed. See the Accessibility guidelines to learn more.

accessibilityHaspopup
boolean
-

Set as true if Button controls one or more interactive popup elements, such as a menu or dialog. See the Accessibility guidelines to learn more.

accessibilityLabel
string
-

Label to provide more context around Button’s function or purpose. See the Accessibility guidelines to learn more.

color
"gray" | "red" | "blue" | "transparent" |  "semiTransparentWhite" | "transparentWhiteText" | "white"
"gray"

The background color of Button.

disabled
boolean
false

Indicates if Button is disabled. Disabled Buttons are inactive and cannot be interacted with.

fullWidth
boolean
false

Default Buttons are sized by the text within the Button whereas full-width Buttons expand to the full width of their container.

href
string
-

Specifies a link URL. Required with role="link" Buttons.

iconEnd
$Keys<typeof icons>
-

An icon displayed after the text to help clarify the usage of Button. See the icon variant to learn more.

onClick
({ event: SyntheticMouseEvent<HTMLButtonElement> | SyntheticKeyboardEvent<HTMLButtonElement> | SyntheticMouseEvent<HTMLAnchorElement> | SyntheticKeyboardEvent<HTMLAnchorElement>, {| dangerouslyDisableOnNavigation: () => void |}> }) => void
-

Callback invoked when the user clicks (press and release) on Button with the mouse or keyboard. Required with role="button" or type="button" Buttons.

See OnLinkNavigationProvider to learn more about link navigation.

ref
React.Ref<"button"> | React.Ref<"a">
-

A React ref to forward to the underlying element.

rel
"none" | "nofollow"
"none"

Optional with link-role Buttons.

role
"button" | "link"
"button"

Use “link” to indicate Button that is acting as an <a> link.

selected
boolean
false

Indicates if Button is currently selected.

size
"sm" | "md" | "lg"
"md"

sm: 32px, md: 40px, lg: 48px

tabIndex
-1 | 0
0

Use "-1" to remove Button from keyboard navigation. See the Accessibility guidelines to learn more.

target
null | "self" | "blank"
"null"

Indicates the browsing context where an href will be opened. Optional with role="link" Buttons.

type
"submit" | "button"
"button"

Use “submit” if Button is used within or associated with a form.

Usage guidelines

When to use
  • Communicating an action that will occur.
  • Triggering or enabling an action, such as submitting requested information.
  • Progressing or regressing a user through a step in a flow.
When not to use
  • Directing users to a new page or different part within the same page. Instead, use Link.
  • Limited space available. Consider using an IconButton instead.

Best practices

Do

Place primary Buttons to the right or top of other Button styles.

Don't

Place more than one primary Button per container/area.

Do

Show the full text on Buttons. Buttons should be stacked when they cannot be displayed side by side.

Don't

Truncate the Button text. In rare instances where Buttons must remain on one line, truncate the text on the secondary Button before truncating on the primary Button.

Do

Keep the Button text as simple and actionable as possible. Refer to the Button writing guidelines for more detail. If text is not sufficient for accessibility, refer to Accessibility guidelines for more detail.

Don't

Do not add icons to a Button to reinforce the text.

Do

Use an IconButton + Tooltip next to the disabled Button if you need to explain why it is disabled.

Don't

Use a Tooltip on disabled Button, as it is not accessible for keyboard and screen reader users.

Accessibility

ARIA attributes

When Button text does not provide sufficient context about the Button’s behavior, supply a short, descriptive label for screen-readers using accessibilityLabel.
Texts like “Click here“, “Follow“, or “Shop“ can be confusing when a screen reader reads them out of context. In those cases, we must pass an alternative text with deeper context to replace the Button text, like “Follow Ryan” or “Shop Wedding Invitations”.

If Button is used as a control Button to show/hide a Popover-based component, we recommend passing the following ARIA attributes to assist screen readers:

  • accessibilityLabel: if present, read by screen readers read instead of the text prop.
  • accessibilityControls: informs the screen reader that Button controls the display of an anchored Popover-based component. It populates aria-controls.
  • accessibilityHaspopup: informs the screen reader that there’s a Popover-based component attached to Button. It populates aria-haspopup.
  • accessibilityExpanded: informs the screen reader whether the button-anchored Popover-based component is currently open or closed. It populates aria-expanded.

Localization

Be sure to localize text and accessibilityLabel. Note that localization can lengthen text by 20 to 30 percent. Avoid truncating Button text whenever possible. Refer to the Button usage guidelines for more information.

Buttons with link role announce to assistive technologies that the link opens in a new tab when setting target to 'blank'. Localize the default label with DefaultLabelProvider. Learn more

Variants

Size

Button is available in 3 fixed sizes. The Button text has always a fixed size of 16px:

  1. lg (48px)
    Large is the only size that should be used on Pinner surfaces.
  2. md (40px)
    Medium is used on more dense UI such as business surfaces or internal tools.
  3. sm (32px)
    Small should be used sparingly and only in places where the UI is very dense.
size="sm"
size="md"
size="lg"

Width

  1. Inline (default)
    Inline is our default Button width. The width of an inline Button is based on the length of its text. Use in most cases where you need a Button.
  2. Full-width (fullWidth)
    Full-width Buttons can be used in narrower content areas when the text in the Button is close to full width in the content area. This is especially common to see in components such as Callout and Upsell at their smaller breakpoints.
false
fullwidth

Color on white backgrounds

  1. Red (Primary)
    High emphasis, used for primary actions.
  2. Blue (Primary in shopping context)
    The blue Button is only intended for the shopping experience and is used for primary shopping actions.
  3. Gray (Secondary)
    Medium emphasis, used for secondary actions.
  4. Transparent (Tertiary)
    Low emphasis when placed on dark/image backgrounds, used for tertiary actions in that context. Note, this treatment should be used with caution as it has potential color contrast issues.
color="red"
color="blue"
color="gray"
color="transparent"

Color on color/image backgrounds

  1. White (Primary)
    High emphasis when placed on color/image backgrounds, used for primary actions in that context.
  2. Semi-transparent white (Secondary)
    Medium emphasis when placed on color/image backgrounds, used for secondary actions in that context.
import { useState, useRef, useEffect } from 'react';
import {
  Box,
  Button,
  Flex,
  Layer,
  Popover,
  ScrollBoundaryContainer,
  Tabs,
  Text,
} from 'gestalt';

export default function WhiteButtonExample() {
  const [open, setOpen] = useState(false);
  const anchorRef = useRef();
  const viewRef = useRef();

  useEffect(() => {
    setOpen(true);
  }, []);

  return (
    <ScrollBoundaryContainer>
      <Box ref={viewRef}>
        <Box
          display="flex"
          justifyContent="center"
          alignItems="center"
          width="100%"
          ref={anchorRef}
        >
          <Tabs
            activeTabIndex={0}
            onChange={() => {}}
            tabs={[{ href: '#Anchor', text: 'Created' }]}
          />
        </Box>
      </Box>
      {open && (
        <Layer>
          <Popover
            anchor={anchorRef.current}
            color="blue"
            idealDirection="down"
            showCaret
            onDismiss={() => {}}
            positionRelativeToAnchor={false}
            size={240}
          >
            <Box padding={3}>
              <Flex
                alignItems="center"
                direction="column"
                gap={{ column: 4, row: 0 }}
              >
                <Text color="light" align="center">
                  New look! Click Created to see Pins you`ve published. Click
                  Saved to see your saved Pins and boards.
                </Text>
                <Button color="white" size="lg" text="Got it" />
              </Flex>
            </Box>
          </Popover>
        </Layer>
      )}
    </ScrollBoundaryContainer>
  );
}
import { useState, useEffect, useRef } from 'react';
import {
  Box,
  Button,
  Flex,
  Layer,
  Popover,
  ScrollBoundaryContainer,
  Tabs,
  Text,
} from 'gestalt';

export default function SemiTransparentWhiteButtonExample() {
  const [open, setOpen] = useState(false);
  const anchorRef = useRef();
  const viewRef = useRef();

  useEffect(() => {
    setOpen(true);
  }, []);

  return (
    <ScrollBoundaryContainer>
      <Box ref={viewRef}>
        <Box display="flex" justifyContent="center" ref={anchorRef}>
          <Tabs
            activeTabIndex={0}
            onChange={() => {}}
            tabs={[{ href: '#Anchor', text: 'Created' }]}
          />
        </Box>
      </Box>
      {open && (
        <Layer>
          <Popover
            anchor={anchorRef.current}
            color="blue"
            idealDirection="down"
            showCaret
            onDismiss={() => {}}
            positionRelativeToAnchor={false}
            size={240}
          >
            <Box padding={3}>
              <Flex
                alignItems="center"
                direction="column"
                gap={{ column: 4, row: 0 }}
              >
                <Text color="light" align="center">
                  New look! Click Created to see Pins you`ve published. Click
                  Saved to see your saved Pins and boards.
                </Text>
                <Flex
                  alignItems="stretch"
                  direction="column"
                  gap={{ column: 2, row: 0 }}
                >
                  <Button color="white" size="lg" text="Got it" fullWidth />
                  <Button
                    color="semiTransparentWhite"
                    size="lg"
                    text="Learn more"
                    fullWidth
                  />
                </Flex>
              </Flex>
            </Box>
          </Popover>
        </Layer>
      )}
    </ScrollBoundaryContainer>
  );
}

Icons

iconEnd adds an icon after the Button text. Icons should only be used to visually reinforce a specific function or interaction of the Button. Menus and external links are a common use case. Use visit when linking to an external URL or arrow-down when displaying a Popover on click. Note that iconEnd on Button is not accessible to screen readers.

Use Gestalt's ESLint rule to enforce the correct icons usage in Button. Learn more about the "button-icon-restrictions" rule
import { Button, Flex } from 'gestalt';

export default function Example() {
  return (
    <Flex
      alignItems="center"
      height="100%"
      justifyContent="center"
      width="100%"
    >
      <Button
        accessibilityLabel="Menu"
        iconEnd="arrow-down"
        size="lg"
        text="Menu"
      />
    </Flex>
  );
}

Role

  1. Button (default)
    The “button” role is used for actions. This is the default and should be used for most Buttons.
  2. Link
    The “link” role is used for navigating by URL. These Buttons should not use a selected state.
import { Button, Flex } from 'gestalt';

export default function Example() {
  return (
    <Flex
      alignItems="center"
      height="100%"
      justifyContent="center"
      width="100%"
    >
      <Button
        accessibilityLabel="Follow"
        size="lg"
        text="Follow"
        role="button"
      />
    </Flex>
  );
}
import { Button, Flex } from 'gestalt';

export default function Example() {
  return (
    <Flex
      alignItems="center"
      height="100%"
      justifyContent="center"
      width="100%"
    >
      <Button
        accessibilityLabel="Visit Pinterest"
        iconEnd="visit"
        size="lg"
        text="Visit Pinterest"
        role="link"
        href="https://pinterest.com"
      />
    </Flex>
  );
}

rel and target

These optional props control the behavior of role="link" Buttons. External links commonly use target="_blank" to open the link in a new tab or window, and rel="nofollow" to provide hints for SEO.

Button with link role announces to assistive technologies that the link opens in a new tab. Localize the default label with DefaultLabelProvider. Learn more
import { Button, Flex } from 'gestalt';

export default function Example() {
  return (
    <Flex
      alignItems="center"
      height="100%"
      justifyContent="center"
      width="100%"
    >
      <Button
        accessibilityLabel="Visit Pinterest"
        iconEnd="visit"
        size="lg"
        text="Visit Pinterest"
        role="link"
        rel="nofollow"
        target="blank"
        href="#"
      />
    </Flex>
  );
}

States

  1. Default
    The typical state of a Button that represents it can be interacted with and is not in a selected state.
  2. Disabled
    Used to block user interaction such as hover, focus and click. Disabled Buttons are completely unreachable by a keyboard and screenreader, so do not attach Tooltips to disabled Buttons.
  3. Selected
    When Button is used to toggle a boolean state or control the visibility of other elements (e.g. Dropdown), use the selected prop to indicate the current state. Do not use this prop with role="link" Buttons.
import { Button, Flex } from 'gestalt';

export default function Example() {
  return (
    <Flex
      alignItems="center"
      height="100%"
      justifyContent="center"
      width="100%"
    >
      <Button accessibilityLabel="Save" color="red" text="Save" size="lg" />
    </Flex>
  );
}
import { Button, Flex } from 'gestalt';

export default function Example() {
  return (
    <Flex
      alignItems="center"
      height="100%"
      justifyContent="center"
      width="100%"
    >
      <Button accessibilityLabel="Submit" disabled text="Submit" size="lg" />{' '}
    </Flex>
  );
}
import { Button, Flex } from 'gestalt';

export default function Example() {
  return (
    <Flex
      alignItems="center"
      height="100%"
      justifyContent="center"
      width="100%"
    >
      <Button
        accessibilityLabel="Following"
        text="Following"
        selected
        size="lg"
      />
    </Flex>
  );
}

Accessibility props: controls, expanded, & popup

import { useState, useRef } from 'react';
import { Button, Dropdown, Box } from 'gestalt';

export default function ActionDropdownExample() {
  const [open, setOpen] = useState(false);
  const [selected, setSelected] = useState(null);
  const anchorRef = useRef(null);

  const onSelect = ({ item }) => setSelected(item);

  return (
    <Box padding={8} display="flex" justifyContent="center" width="100%">
      <Button
        accessibilityControls="action-variant-dropdown-example"
        accessibilityExpanded={open}
        accessibilityHaspopup
        iconEnd="arrow-down"
        onClick={() => setOpen((prevVal) => !prevVal)}
        ref={anchorRef}
        selected={open}
        size="lg"
        text={selected ? selected.label : 'Display'}
      />
      {open && (
        <Dropdown
          anchor={anchorRef.current}
          id="action-variant-dropdown-example"
          onDismiss={() => setOpen(false)}
        >
          <Dropdown.Item
            onSelect={onSelect}
            option={{ value: 'Cozy', label: 'Cozy' }}
            selected={selected}
          />
          <Dropdown.Item
            onSelect={onSelect}
            option={{ value: 'Comfy', label: 'Comfy' }}
            selected={selected}
          />
        </Dropdown>
      )}
    </Box>
  );
}

Ref

To control focus or position anchored components relative to Button, use ref as shown in the example below.

import { useState, useRef } from 'react';
import { Box, Button, Popover, Text } from 'gestalt';

export default function ButtonPopoverExample() {
  const [selected, setSelected] = useState(false);
  const anchorRef = useRef(null);

  return (
    <Box padding={8} display="flex" justifyContent="center" width="100%">
      <Button
        onClick={() => setSelected(!selected)}
        ref={anchorRef}
        selected={selected}
        text={selected ? 'Hide Popover' : 'Show Popover'}
        iconEnd="arrow-down"
      />
      {selected && (
        <Popover
          anchor={anchorRef.current}
          idealDirection="right"
          onDismiss={() => setSelected(false)}
          shouldFocus={false}
        >
          <Box padding={3}>
            <Text weight="bold">
              This is a Button with an anchor ref to a Popover component
            </Text>
          </Box>
        </Popover>
      )}
    </Box>
  );
}

Writing

Do
  • If your object is already described on the screen, Buttons only need a verb (Example: Save).
  • If your object isn’t described on the screen, Buttons need a verb + the object (Example: Create Pin).
  • Use fewer than 3 words.
  • Use sentence case.
Don't
  • Do not use punctuation.

Component quality checklist

Component quality checklist
Quality item
Status
Status description
Figma Library
Ready
Component is available in Figma across all platforms.
Responsive Web
Ready
Component is available in code for web and mobile web.
iOS
Planned
Component is slotted to be built for iOS.
Android
Planned
Component is slotted to be built for Android.

ButtonGroup
When displaying multiple Buttons in a layout, use ButtonGroup to ensure consistent spacing and wrapping behavior.

IconButton
Use IconButton when only an icon is needed instead of text.

TapArea
Use TapArea to make non-button elements interactive, like an Image. This ensures the element interaction is accessible and uses Gestalt styles.

Tabs
Tabs are intended for page-level navigation between multiple URLs.

OnLinkNavigationProvider
OnLinkNavigationProvider allows external link navigation control across all children components with link behavior.
See OnLinkNavigationProvider to learn more about link navigation.