Frontfriend
Components

Button

A versatile button component with multiple variants, sizes, icon support, and loading states.

Button

Displays a button or a component that looks like a button with extensive customization options.

Installation

Download the Button component using the Frontfriend CLI:

npx frontfriend download button

This will install the Button component along with its dependencies (Icon, Spinner components).

Usage

import { Button } from '@/components/ui/button';
 
export default function Demo() {
  return <Button variant="main">Click me</Button>;
}

API Reference

Props

PropTypeDefaultDescription
variant'main' | 'destructive' | 'tertiary' | 'secondary' | 'ghost' | 'ghostmain' | 'link' | 'linkDestructive''main'Visual style variant
size'default' | 'sm' | 'lg''default'Button size
iconkeyof typeof iconsundefinedIcon to display
iconPosition'prefix' | 'suffix' | 'default''default'Icon position. Use 'default' for icon-only buttons
loadingbooleanfalseShow loading spinner
loadingTextstringundefinedCustom text to show during loading
asChildbooleanfalseCompose with child element using Radix Slot
...restReact.ButtonHTMLAttributes-All standard button HTML attributes

Examples

Variants

The Button component supports 8 different visual variants to match different use cases.

import { Button } from '@/components/ui/button';
 
export default function VariantsDemo() {
  return (
    <div className="flex flex-wrap gap-4">
      <Button variant="main">Main</Button>
      <Button variant="secondary">Secondary</Button>
      <Button variant="tertiary">Tertiary</Button>
      <Button variant="destructive">Destructive</Button>
      <Button variant="ghost">Ghost</Button>
      <Button variant="ghostmain">Ghost Main</Button>
      <Button variant="link">Link</Button>
      <Button variant="linkDestructive">Link Destructive</Button>
    </div>
  );
}

Sizes

Three size options are available: small, default, and large.

import { Button } from '@/components/ui/button';
 
export default function SizesDemo() {
  return (
    <div className="flex items-center gap-4">
      <Button size="sm">Small</Button>
      <Button size="default">Default</Button>
      <Button size="lg">Large</Button>
    </div>
  );
}

With Icons

Buttons can display icons in three different positions: prefix (before text), suffix (after text), or default (icon-only).

Icon Prefix

import { Button } from '@/components/ui/button';
 
export default function IconPrefixDemo() {
  return (
    <Button icon="Mail" iconPosition="prefix">
      Send Email
    </Button>
  );
}

Icon Suffix

import { Button } from '@/components/ui/button';
 
export default function IconSuffixDemo() {
  return (
    <Button icon="ChevronRight" iconPosition="suffix">
      Next
    </Button>
  );
}

Icon Only

import { Button } from '@/components/ui/button';
 
export default function IconOnlyDemo() {
  return (
    <div className="flex gap-2">
      <Button icon="Settings" iconPosition="default" aria-label="Settings" />
      <Button icon="Search" iconPosition="default" aria-label="Search" />
      <Button icon="Heart" iconPosition="default" aria-label="Favorite" />
    </div>
  );
}

Loading State

Display a loading spinner and optional loading text while an async action is in progress.

import { Button } from '@/components/ui/button';
import { useState } from 'react';
 
export default function LoadingDemo() {
  const [isLoading, setIsLoading] = useState(false);
 
  const handleClick = async () => {
    setIsLoading(true);
    await new Promise(resolve => setTimeout(resolve, 2000));
    setIsLoading(false);
  };
 
  return (
    <div className="flex gap-4">
      <Button loading={isLoading} onClick={handleClick}>
        Submit
      </Button>
      <Button
        loading={isLoading}
        loadingText="Saving..."
        onClick={handleClick}
      >
        Save Changes
      </Button>
    </div>
  );
}

As Child (Composition)

Use the asChild prop to compose the Button with other components, such as links.

import { Button } from '@/components/ui/button';
import Link from 'next/link';
 
export default function AsChildDemo() {
  return (
    <Button asChild>
      <Link href="/dashboard">
        Go to Dashboard
      </Link>
    </Button>
  );
}

Disabled State

import { Button } from '@/components/ui/button';
 
export default function DisabledDemo() {
  return (
    <div className="flex gap-4">
      <Button disabled>Disabled Button</Button>
      <Button variant="destructive" disabled>
        Can't Delete
      </Button>
    </div>
  );
}

Design Tokens

The Button component uses design tokens from @frontfriend/tailwind for consistent theming. All colors, spacing, and typography are controlled through the design token system, ensuring consistency across your application.

Accessibility

  • Button includes proper ARIA attributes
  • Icon-only buttons should include an aria-label for screen readers
  • Disabled state is properly communicated to assistive technologies
  • Loading state maintains button focus and communicates status
  • Icon: Used internally for displaying icons
  • Spinner: Used for loading states

On this page