Shopify's comprehensive admin product component library for React applications with TypeScript support and accessibility features.
—
Button variants, action lists, and interactive components for user actions and commands. These components provide consistent interaction patterns, accessibility features, and visual feedback for all user-initiated actions.
Primary button component with multiple variants, sizes, tones, and interaction states for triggering actions.
/**
* Primary button component for triggering actions
* @param children - Button content/label
* @param onClick - Button click handler
* @param variant - Button visual variant
* @param size - Button size
* @returns JSX element with button
*/
function Button(props: ButtonProps): JSX.Element;
interface ButtonProps extends BaseButton {
/** The content to display inside the button */
children?: string | string[];
/** Changes the size of the button, giving it more or less padding */
size?: 'micro' | 'slim' | 'medium' | 'large';
/** Changes the inner text alignment of the button */
textAlign?: 'left' | 'right' | 'center' | 'start' | 'end';
/** Allows the button to grow to the width of its container */
fullWidth?: boolean;
/** Displays the button with a disclosure icon. Defaults to down when set to true */
disclosure?: 'down' | 'up' | 'select' | boolean;
/** Icon to display to the left of the button content */
icon?: React.ReactElement | IconSource;
/** Indicates whether or not the button is the primary navigation link when rendered inside of an IndexTable.Row */
dataPrimaryLink?: boolean;
/** Sets the color treatment of the Button */
tone?: 'critical' | 'success';
/** Changes the visual appearance of the Button */
variant?: 'plain' | 'primary' | 'secondary' | 'tertiary' | 'monochromePlain';
/** Button ID */
id?: string;
/** Accessibility label */
accessibilityLabel?: string;
/** ARIA describedby */
ariaDescribedBy?: string;
/** ARIA expanded state */
ariaExpanded?: boolean;
/** ARIA controls */
ariaControls?: string;
/** Button role */
role?: string;
/** Tab index */
tabIndex?: number;
/** Submit button type */
submit?: boolean;
/** Button URL for link behavior */
url?: string;
/** External link */
external?: boolean;
/** Download attribute */
download?: string | boolean;
/** Link target */
target?: string;
/** Button pressed state */
pressed?: boolean;
/** Removes underline from button text (including on interaction) @deprecated Use a variant instead */
removeUnderline?: boolean;
/** Connector top */
connectedTop?: boolean;
/** Connector bottom */
connectedBottom?: boolean;
/** Connector left */
connectedLeft?: boolean;
/** Connector right */
connectedRight?: boolean;
/** Focus event handler */
onFocus?: () => void;
/** Blur event handler */
onBlur?: () => void;
/** Key down handler */
onKeyDown?: (event: React.KeyboardEvent) => void;
/** Key press handler */
onKeyPress?: (event: React.KeyboardEvent) => void;
/** Key up handler */
onKeyUp?: (event: React.KeyboardEvent) => void;
/** Mouse enter handler */
onMouseEnter?: () => void;
/** Touch start handler */
onTouchStart?: () => void;
}Usage Example:
import React, { useState } from 'react';
import { Button, ButtonGroup, InlineStack } from '@shopify/polaris';
function ButtonExamples() {
const [loading, setLoading] = useState(false);
const handleSave = async () => {
setLoading(true);
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 2000));
setLoading(false);
};
return (
<InlineStack gap="400">
{/* Primary actions */}
<Button
variant="primary"
onClick={handleSave}
loading={loading}
>
Save product
</Button>
{/* Secondary actions */}
<Button variant="secondary" tone="critical">
Delete
</Button>
{/* Icon buttons */}
<Button
icon="search"
accessibilityLabel="Search products"
iconOnly
/>
{/* Button group */}
<ButtonGroup>
<Button>Cancel</Button>
<Button variant="primary">Save</Button>
</ButtonGroup>
</InlineStack>
);
}Utility functions for creating buttons from action objects and converting action arrays to button arrays.
/**
* Create Button component from Action object
* @param action - Action configuration
* @param overrides - Button prop overrides
* @returns JSX element with button from action
*/
function buttonFrom(
action: Action,
overrides?: Partial<ButtonProps>
): JSX.Element;
/**
* Create Button array from Action array
* @param actions - Array of action configurations
* @param overrides - Button prop overrides for all buttons
* @returns Array of JSX elements with buttons from actions
*/
function buttonsFrom(
actions: Action[],
overrides?: Partial<ButtonProps>
): JSX.Element[];Unstyled button base component providing button functionality without Polaris styling.
/**
* Unstyled button base component
* @param children - Button content
* @param onClick - Click handler
* @param disabled - Disabled state
* @returns JSX element with unstyled button
*/
function UnstyledButton(props: UnstyledButtonProps): JSX.Element;
interface UnstyledButtonProps {
/** Button content */
children?: React.ReactNode;
/** Click handler */
onClick?: () => void;
/** Disabled state */
disabled?: boolean;
/** Loading state */
loading?: boolean;
/** Accessibility label */
accessibilityLabel?: string;
/** ARIA describedby */
ariaDescribedBy?: string;
/** ARIA expanded */
ariaExpanded?: boolean;
/** ARIA controls */
ariaControls?: string;
/** ARIA pressed */
ariaPressed?: boolean;
/** Button ID */
id?: string;
/** Tab index */
tabIndex?: number;
/** Button role */
role?: string;
/** Button type */
type?: 'button' | 'submit' | 'reset';
/** Button URL */
url?: string;
/** External link */
external?: boolean;
/** Download attribute */
download?: string | boolean;
/** Link target */
target?: string;
/** Additional class names */
className?: string;
/** Focus handler */
onFocus?: () => void;
/** Blur handler */
onBlur?: () => void;
/** Key down handler */
onKeyDown?: (event: React.KeyboardEvent) => void;
/** Key press handler */
onKeyPress?: (event: React.KeyboardEvent) => void;
/** Key up handler */
onKeyUp?: (event: React.KeyboardEvent) => void;
/** Mouse enter handler */
onMouseEnter?: () => void;
/** Touch start handler */
onTouchStart?: () => void;
}
/**
* Create UnstyledButton from Action object
* @param action - Action configuration
* @param overrides - Button prop overrides
* @returns JSX element with unstyled button from action
*/
function unstyledButtonFrom(
action: Action,
overrides?: Partial<UnstyledButtonProps>
): JSX.Element;Group multiple buttons with consistent spacing and connected styling options.
/**
* Group buttons with consistent spacing and styling
* @param children - Button components
* @param segmented - Connected button styling
* @param fullWidth - Full width button group
* @returns JSX element with button group
*/
function ButtonGroup(props: ButtonGroupProps): JSX.Element;
interface ButtonGroupProps {
/** Button components */
children?: React.ReactNode;
/** Connected button styling */
segmented?: boolean;
/** Full width buttons */
fullWidth?: boolean;
/** Connector top */
connectedTop?: boolean;
/** Connector bottom */
connectedBottom?: boolean;
/** Button group variant */
variant?: 'segmented';
}List of clickable actions with icons, descriptions, and keyboard navigation support.
/**
* List of clickable actions with icons and descriptions
* @param items - Action items to display
* @param sections - Grouped action sections
* @param onActionAnyItem - Global action handler
* @returns JSX element with action list
*/
function ActionList(props: ActionListProps): JSX.Element;
interface ActionListProps {
/** Individual action items */
items?: ActionListItemDescriptor[];
/** Grouped action sections */
sections?: ActionListSection[];
/** Action role for accessibility */
actionRole?: string;
/** Global action handler */
onActionAnyItem?: ActionListItemDescriptor['onAction'];
}
interface ActionListItemDescriptor {
/** Action content/label */
content?: React.ReactNode;
/** Action callback */
onAction?(): void;
/** Action URL */
url?: string;
/** External link */
external?: boolean;
/** Action icon */
icon?: IconSource;
/** Action image */
image?: string;
/** Prefix content */
prefix?: React.ReactNode;
/** Suffix content */
suffix?: React.ReactNode;
/** Help text */
helpText?: React.ReactNode;
/** Accessibility label */
accessibilityLabel?: string;
/** Disabled state */
disabled?: boolean;
/** Destructive action */
destructive?: boolean;
/** Ellipsis truncation */
ellipsis?: boolean;
/** Active state */
active?: boolean;
/** Badge content */
badge?: BadgeProps;
/** Role override */
role?: string;
/** Truncate text */
truncate?: boolean;
/** Indentation variant */
variant?: 'default' | 'indented' | 'menu';
}
interface ActionListSection {
/** Section title */
title?: string;
/** Section items */
items: ActionListItemDescriptor[];
/** Fill available space */
fill?: boolean;
}
/**
* Individual action list item component
* @param content - Item content
* @param onAction - Action handler
* @param icon - Item icon
* @returns JSX element with action item
*/
function ActionListItem(props: ActionListItemProps): JSX.Element;
interface ActionListItemProps extends ActionListItemDescriptor {
/** Item index for keyboard navigation */
index?: number;
}Menu component for displaying grouped actions with overflow handling and responsive behavior.
/**
* Menu for displaying grouped actions with overflow handling
* @param groups - Action groups to display
* @param actions - Individual actions
* @param rollup - Overflow rollup configuration
* @returns JSX element with action menu
*/
function ActionMenu(props: ActionMenuProps): JSX.Element;
interface ActionMenuProps {
/** Action groups */
groups?: MenuGroupDescriptor[];
/** Individual actions */
actions?: MenuActionDescriptor[];
/** Overflow rollup behavior */
rollup?: boolean;
/** Rollup actions configuration */
rollupActionsLabel?: string;
/** Callback when menu opens */
onOpen?(): void;
/** Callback when menu closes */
onClose?(): void;
}
interface MenuGroupDescriptor {
/** Group title */
title?: string;
/** Group actions */
actions: MenuActionDescriptor[];
/** Group icon */
icon?: IconSource;
/** Details content */
details?: React.ReactNode;
/** Disabled state */
disabled?: boolean;
}
interface MenuActionDescriptor extends ActionListItemDescriptor {
/** Help text tooltip */
helpText?: string;
/** Action index for positioning */
index?: number;
}Page-level action buttons positioned consistently in page headers with primary and secondary action support.
/**
* Page-level action buttons for page headers
* @param primaryAction - Primary page action
* @param secondaryActions - Secondary page actions
* @returns JSX element with page actions
*/
function PageActions(props: PageActionsProps): JSX.Element;
interface PageActionsProps {
/** Primary page action */
primaryAction?: ComplexAction;
/** Secondary page actions */
secondaryActions?: ComplexAction[];
}
interface ComplexAction extends Action {
/** Accessibility label */
accessibilityLabel?: string;
/** Disabled state */
disabled?: boolean;
/** Destructive styling */
destructive?: boolean;
/** External link */
external?: boolean;
/** Help text */
helpText?: React.ReactNode;
/** Action icon */
icon?: IconSource;
/** Action ID */
id?: string;
/** Loading state */
loading?: boolean;
/** Outline variant */
outline?: boolean;
/** Plain variant */
plain?: boolean;
/** Primary styling */
primary?: boolean;
/** Remove underline */
removeUnderline?: boolean;
/** Size variant */
size?: 'slim' | 'medium' | 'large';
/** Submit button */
submit?: boolean;
/** Target for links */
target?: Target;
/** Tooltip content */
tooltip?: string;
}Usage Example:
import React from 'react';
import { ActionList, ActionMenu, Popover, Button } from '@shopify/polaris';
function ActionsExample() {
const [active, setActive] = React.useState(false);
const actionItems = [
{
content: 'Edit product',
icon: 'edit',
onAction: () => console.log('Edit clicked'),
},
{
content: 'Duplicate product',
icon: 'duplicate',
onAction: () => console.log('Duplicate clicked'),
},
{
content: 'Archive product',
icon: 'archive',
destructive: true,
onAction: () => console.log('Archive clicked'),
},
];
const menuGroups = [
{
title: 'Promote',
actions: [
{
content: 'Share on social media',
icon: 'share',
onAction: () => console.log('Share clicked'),
},
],
},
{
title: 'Organize',
actions: [
{
content: 'Add to collection',
icon: 'collection',
onAction: () => console.log('Add to collection'),
},
{
content: 'Add tags',
icon: 'tag',
onAction: () => console.log('Add tags'),
},
],
},
];
const activator = (
<Button
disclosure
onClick={() => setActive(!active)}
>
More actions
</Button>
);
return (
<>
{/* Simple action list */}
<ActionList items={actionItems} />
{/* Action menu with groups */}
<Popover
active={active}
activator={activator}
onClose={() => setActive(false)}
>
<ActionMenu groups={menuGroups} />
</Popover>
</>
);
}/** Base action interface */
interface Action {
/** Action content/label */
content?: string;
/** Accessibility label */
accessibilityLabel?: string;
/** Action URL */
url?: string;
/** External link */
external?: boolean;
/** Action callback */
onAction?(): void;
/** Mouse enter handler */
onMouseEnter?(): void;
/** Touch start handler */
onTouchStart?(): void;
}
/** Link action with required URL */
interface LinkAction extends Action {
/** Required URL for link actions */
url: string;
}
/** Callback action with required handler */
interface CallbackAction extends Action {
/** Required callback for action */
onAction(): void;
}
/** Disableable action interface */
interface DisableableAction extends Action {
/** Disabled state */
disabled?: boolean;
}
/** Destructable action interface */
interface DestructableAction extends Action {
/** Destructive styling */
destructive?: boolean;
}
/** Iconable action interface */
interface IconableAction extends Action {
/** Action icon */
icon?: IconSource;
}
/** Loadable action interface */
interface LoadableAction extends Action {
/** Loading state */
loading?: boolean;
}
/** Outlineable action interface */
interface OutlineableAction extends Action {
/** Outline variant */
outline?: boolean;
}
/** Plain action interface */
interface PlainAction extends Action {
/** Plain styling variant */
plain?: boolean;
}
/** Tooltip action interface */
interface TooltipAction extends Action {
/** Help text tooltip */
helpText?: React.ReactNode;
}
/** Badge action interface */
interface BadgeAction extends Action {
/** Badge configuration */
badge?: string | BadgeProps;
}
/** Icon source type */
type IconSource = React.ComponentType<any> | 'placeholder' | string;
/** Link target type */
type Target = '_blank' | '_self' | '_parent' | '_top';
/** Badge props interface */
interface BadgeProps {
/** Badge content */
children?: React.ReactNode;
/** Badge tone */
tone?: 'default' | 'success' | 'info' | 'attention' | 'warning' | 'critical';
/** Badge progress */
progress?: 'incomplete' | 'partiallyComplete' | 'complete';
/** Badge size */
size?: 'small' | 'medium';
}Selectable list of options with keyboard navigation, ideal for dropdowns, filters, and selection interfaces.
/**
* Selectable list with keyboard navigation
* @param options - Array of selectable options
* @param selected - Currently selected options
* @param onChange - Selection change handler
* @returns JSX element with option list
*/
function OptionList(props: OptionListProps): JSX.Element;
interface OptionListProps {
/** The title of the option list */
title?: string;
/** Collection of options to be rendered */
options?: SectionDescriptor[] | OptionDescriptor[];
/** The selected options */
selected: string[];
/** Allow more than one option to be selected */
allowMultiple?: boolean;
/** The role for the option list */
role?: string;
/** The option list's section role */
sectionRole?: string;
/** Callback when the selection of options is changed */
onChange(selected: string[]): void;
}Bulk selection controls for data tables and lists with select all, deselect all, and selective actions.
/**
* Bulk selection controls for data lists
* @param label - Label for the select all control
* @param selected - Whether all items are selected
* @param onToggleAll - Toggle all selection handler
* @returns JSX element with select all controls
*/
function SelectAllActions(props: SelectAllActionsProps): JSX.Element;
interface SelectAllActionsProps {
/** Label for the bulk actions */
label?: string;
/** Callback when the selection of all items is changed */
onToggleAll?(): void;
/** Whether to select all items */
selectMode?: boolean;
/** Callback when the select mode is toggled */
onSelectModeToggle?(): void;
}Toggle control for enabling/disabling settings with descriptive labels and contextual actions.
/**
* Toggle control for settings with descriptive labels
* @param action - Toggle action configuration
* @param enabled - Whether setting is enabled
* @param children - Description content
* @returns JSX element with setting toggle
*/
function SettingToggle(props: SettingToggleProps): JSX.Element;
interface SettingToggleProps {
/** The action to toggle the setting */
action?: ComplexAction;
/** Whether the setting is enabled */
enabled?: boolean;
/** The content to display with the setting */
children?: React.ReactNode;
}Accessible listbox component with support for single and multiple selection, keyboard navigation, and custom option rendering.
/**
* Accessible listbox with selection and keyboard navigation
* @param options - Array of listbox options
* @param selected - Currently selected values
* @param onSelect - Selection change handler
* @returns JSX element with listbox interface
*/
function Listbox(props: ListboxProps): JSX.Element;
interface ListboxProps {
/** Enable auto selection behavior */
enableKeyboardControl?: boolean;
/** Collection of options to render */
children?: React.ReactNode;
/** Auto selection mode */
autoSelection?: AutoSelection;
/** Callback when an option is selected */
onSelect?(value: string): void;
/** Callback when the active option changes */
onActiveOptionChange?(value?: string): void;
}
enum AutoSelection {
None = 'NONE',
First = 'FIRST',
Selected = 'SELECTED',
}Tab navigation component for organizing content into switchable panels with keyboard accessibility.
/**
* Tab navigation for organizing content into panels
* @param tabs - Array of tab definitions
* @param selected - Index of selected tab
* @param onSelect - Tab selection handler
* @returns JSX element with tab navigation
*/
function Tabs(props: TabsProps): JSX.Element;
interface TabsProps {
/** Collection of tabs to display */
tabs: TabProps[];
/** The index of the selected tab */
selected: number;
/** Whether the tabs are fitted to the container */
fitted?: boolean;
/** The callback to handle tab selection */
onSelect?(selectedTabIndex: number): void;
/** Visually hide the tab navigation */
disclosureText?: string;
}
interface TabProps {
/** A unique identifier for the tab */
id: string;
/** Content to display in the tab */
content: React.ReactNode;
/** Accessible label for the tab */
accessibilityLabel?: string;
/** URL for the tab */
url?: string;
/** Badge content */
badge?: React.ReactNode;
/** Panel content */
panelID?: string;
}Legacy tab component for backward compatibility with older tab implementations.
/**
* Legacy tab component for backward compatibility
* @param tabs - Array of legacy tab definitions
* @param selected - Index of selected tab
* @param onSelect - Tab selection handler
* @returns JSX element with legacy tab navigation
*/
function LegacyTabs(props: LegacyTabsProps): JSX.Element;
interface LegacyTabsProps {
/** Collection of tabs to display */
tabs: LegacyTab[];
/** The index of the selected tab */
selected: number;
/** Whether the tabs are fitted to the container */
fitted?: boolean;
/** The callback to handle tab selection */
onSelect?(selectedTabIndex: number): void;
}
interface LegacyTab {
/** A unique identifier for the tab */
id: string;
/** The title of the tab */
title: string;
/** URL for the tab */
url?: string;
/** Badge content */
badge?: React.ReactNode;
}Install with Tessl CLI
npx tessl i tessl/npm-shopify--polaris