Thrive Design System

Components

Button

A clickable element which communicates that users can trigger an action

Installation

npm install @thrivecart/ui
yarn add @thrivecart/ui
pnpm add @thrivecart/ui
bun add @thrivecart/ui

Usage

Import the Button component from the package. For examples with icons, you'll also need to import from react-icons/md:

import { Button } from '@thrivecart/ui';
import { MdAdd, MdSave, MdEdit, MdArrowForward, MdDownload, MdOpenInNew, MdDelete } from 'react-icons/md';

Examples

Basic Button

Default Button

The simplest form of a button

<Button>Click me</Button>

Variants

Buttons come in different visual styles to indicate their importance and purpose.

Button Variants

Different visual styles for different use cases

<div className="flex flex-wrap gap-2">
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="destructive">Destructive</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="ghost-body">Ghost Body</Button>
<Button variant="ghost-destructive">Ghost Destructive</Button>
<Button variant="link">Link</Button>
</div>

Sizes

Buttons are available in four sizes to fit different contexts and density needs.

Button Sizes

Four size options from extra small to large

<div className="flex items-center gap-2">
<Button size="xs">Extra Small</Button>
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
</div>

Size recommendations:

  • xs: Compact spaces, tables, crowded interfaces
  • sm: Default density interfaces, secondary actions
  • md: Default size for most primary actions
  • lg: Prominent calls-to-action, hero sections

With Icons

Buttons support icons on both the left and right sides, or as standalone icon-only buttons.

Using leftIcon and rightIcon props:

Buttons with Left Icons

Use the leftIcon prop for icons before text

<div className="flex flex-wrap gap-2">
<Button variant="primary" leftIcon={<MdAdd />}>
  Add Item
</Button>
<Button leftIcon={<MdSave />}>
  Save Changes
</Button>
<Button variant="secondary" leftIcon={<MdEdit />}>
  Edit
</Button>
</div>

Right side icons:

Buttons with Right Icons

Use the rightIcon prop for icons after text

<div className="flex flex-wrap gap-2">
<Button variant="primary" rightIcon={<MdArrowForward />}>
  Continue
</Button>
<Button rightIcon={<MdDownload />}>
  Download
</Button>
<Button variant="link" rightIcon={<MdOpenInNew />}>
  Open Link
</Button>
</div>

Loading State

Buttons can display a loading state to provide feedback during async operations.

Loading Buttons

Show loading state during async operations

<div className="flex flex-wrap gap-2">
<Button variant="primary" loading disabled>
  Processing...
</Button>
<Button variant="primary" loading loadingText="Saving..." disabled>
  Save Changes
</Button>
<Button variant="secondary" loading disabled>
  Loading
</Button>
<Button variant="destructive" loading loadingText="Deleting..." disabled>
  Delete
</Button>
</div>

Loading state behavior:

  • Automatically disables the button
  • Shows a spinning loader icon
  • Optionally shows custom loadingText
  • Hides icons while loading

Disabled State

Disabled Buttons

Buttons that are temporarily unavailable

<div className="flex flex-wrap gap-2">
<Button variant="primary" disabled>Primary Disabled</Button>
<Button variant="secondary" disabled>Secondary Disabled</Button>
<Button variant="destructive" disabled>Destructive Disabled</Button>
<Button variant="ghost" disabled>Ghost Disabled</Button>
</div>

Destructive Actions

Use the destructive variant for actions that have permanent consequences like deleting data or canceling subscriptions.

Destructive Actions

Highlight permanent and dangerous actions

<div className="flex flex-wrap gap-2">
<Button variant="destructive">Delete Account</Button>
<Button variant="destructive" leftIcon={<MdDelete />}>
  Remove Item
</Button>
<Button variant="primary">Save Changes</Button>
</div>

You can render a button as a link element using the asChild prop, which is useful for semantic HTML.

Button as Link

Render button styles on a link element

<div className="flex flex-wrap gap-2">
<Button variant="primary" asChild>
  <a href="/dashboard">Go to Dashboard</a>
</Button>
<Button variant="link" asChild>
  <a href="/documentation">Read Docs</a>
</Button>
</div>

Semantic HTML

When using asChild, the button style is applied to the child element. This is useful when you need proper <a> tags for SEO or when integrating with Next.js Link components.

Best Practices

Use action-oriented labels

Button text should clearly describe the action that will occur. Use verbs: "Save changes", "Delete account", "Add to cart", "Submit form".

Provide loading feedback

Always show loading state during async operations to prevent users from clicking multiple times and to provide clear feedback.

Use appropriate size for context

Match button size to importance and density: xs/sm for tables and toolbars, md for forms, lg for prominent CTAs.

Choose the right variant

Use primary for main actions, secondary/destructive for important but not primary actions, ghost/link for subtle actions, and destructive for dangerous operations.

Avoid vague labels

Don't use generic text like "Click here", "OK", "Submit". Be specific about what will happen.

Don't use multiple primary buttons

Only one primary action per interface. Multiple primary buttons create confusion about hierarchy and importance.

Don't use buttons for navigation

Use <Link> or the asChild prop when navigating between pages. Save buttons for actions that change state.

Don't forget disabled states

Disable buttons when actions aren't available. Provide clear feedback about why an action is disabled.

Props

Props

Accessibility

Keyboard Navigation

Buttons can be activated using the Space or Enter key when focused. Use Tab to navigate between buttons.

Button vs Link

Use a button for actions that affect the current page. Use a link for navigation to different pages or sections.