Button

Action button component used across PyColors UI, built on shadcn/ui. Includes variants, sizes, and best practices.

The Button component is one of the core interactive elements of PyColors UI. It provides consistent styling, variants, accessibility, and flexible composition across marketing pages, dashboards, and applications.

This implementation extends the shadcn/ui button primitive and integrates smoothly with the PyColors design system.


Import

import { Button } from "@/components/ui/button";

Usage

<Button>Click me</Button>
import { Button } from "@/components/ui/button";

export default function Demo() {
  return <Button>Click me</Button>;
}

The default button uses the primary color from the PyColors theme and adapts automatically to light/dark mode.


Variants

Buttons support several variants to adapt to different contexts.

<div className="flex flex-wrap gap-4">
  <Button variant="default">Default</Button>
  <Button variant="secondary">Secondary</Button>
  <Button variant="outline">Outline</Button>
  <Button variant="ghost">Ghost</Button>
  <Button variant="destructive">Destructive</Button>
  <Button variant="link">Link</Button>
</div>
import { Button } from "@/components/ui/button";

export default function ButtonVariantsExample() {
  return (
    <div className="flex flex-wrap gap-4">
      <Button variant="default">Default</Button>
      <Button variant="secondary">Secondary</Button>
      <Button variant="outline">Outline</Button>
      <Button variant="ghost">Ghost</Button>
      <Button variant="destructive">Destructive</Button>
      <Button variant="link">Link</Button>
    </div>
  );
}

Available variants

VariantDescription
defaultPrimary action button, high emphasis
secondaryNeutral alternative to primary
outlineBordered button for medium emphasis
ghostMinimal UI footprint
destructiveUsed for destructive actions
linkText-style button for inline actions

Sizes

<div className="flex items-center gap-4 flex-wrap">
  <Button size="sm">Small</Button>
  <Button size="default">Default</Button>
  <Button size="lg">Large</Button>
  <Button size="icon" aria-label="History">
    <svg
      className="size-4"
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 20 20"
      fill="currentColor"
    >
      <path
        fillRule="evenodd"
        d="M10 1a9 9 0 100 18 9 9 0 000-18zM9 5a1 1 0 012 0v5a1 1 0 01-.293.707l-3 3a1 1 0 11-1.414-1.414L9 9.586V5z"
        clipRule="evenodd"
      />
    </svg>
  </Button>
</div>
import { Button } from "@/components/ui/button";

export default function ButtonSizesExample() {
  return (
    <div className="flex items-center gap-4 flex-wrap">
      <Button size="sm">Small</Button>
      <Button size="default">Default</Button>
      <Button size="lg">Large</Button>
      <Button size="icon" aria-label="History">
        <svg
          className="size-4"
          xmlns="http://www.w3.org/2000/svg"
          viewBox="0 0 20 20"
          fill="currentColor"
        >
          <path
            fillRule="evenodd"
            d="M10 1a9 9 0 100 18 9 9 0 000-18zM9 5a1 1 0 012 0v5a1 1 0 01-.293.707l-3 3a1 1 0 11-1.414-1.414L9 9.586V5z"
            clipRule="evenodd"
          />
        </svg>
      </Button>
    </div>
  );
}

Available sizes

SizeDescription
smCompact buttons for dense UIs
defaultStandard button size
lgLarger visual weight
iconSquare icon-only button

Disabled state

<div className="flex gap-4">
  <Button disabled>Disabled</Button>
  <Button variant="secondary" disabled>
    Disabled
  </Button>
</div>
import { Button } from "@/components/ui/button";

export default function ButtonDisabledExample() {
  return (
    <div className="flex gap-4">
      <Button disabled>Disabled</Button>
      <Button variant="secondary" disabled>
        Disabled
      </Button>
    </div>
  );
}

Disabled buttons use pointer-events-none and reduced opacity to indicate non-interactivity.


With icon

Use any icon library (Lucide, Heroicons, custom SVG).

Leading icon

<Button>
  <svg className="size-4 mr-2" aria-hidden="true" />
  Add item
</Button>
import { Button } from "@/components/ui/button";

export default function ButtonWithIconExample() {
  return (
    <Button>
      <svg
        className="size-4 mr-2"
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        strokeWidth="2"
        aria-hidden="true"
      >
        <path d="M12 5v14m7-7H5" />
      </svg>
      Add item
    </Button>
  );
}

Trailing icon

<Button>
  Continue
  <svg className="size-4 ml-2" aria-hidden="true" />
</Button>
import { Button } from "@/components/ui/button";

export default function ButtonTrailingIconExample() {
  return (
    <Button>
      Continue
      <svg
        className="size-4 ml-2"
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        strokeWidth="2"
        aria-hidden="true"
      >
        <path d="M9 5l7 7-7 7" />
      </svg>
    </Button>
  );
}

As child (Slot)

You can render the button as another component using asChild.

<Button asChild>
  <a href="#docs">Go to docs</a>
</Button>
import { Button } from "@/components/ui/button";

export default function ButtonAsChildExample() {
  return (
    <Button asChild>
      <a href="#docs">Go to docs</a>
    </Button>
  );
}

This allows styling links, router components, or custom components as buttons while maintaining semantics.


API

Props

PropTypeDefaultDescription
variantButtonVariant"default"Visual style of the button
sizeButtonSize"default"Size of the button
asChildbooleanfalseRender using Radix Slot
disabledbooleanfalseDisable interaction
classNamestringAdditional Tailwind classes

The Button extends the standard HTML button props:

React.ButtonHTMLAttributes<HTMLButtonElement>

TypeScript types

These types define the public API for the variant and size props.

export type ButtonVariant =
  | "default"
  | "secondary"
  | "outline"
  | "ghost"
  | "destructive"
  | "link";

export type ButtonSize =
  | "sm"
  | "default"
  | "lg"
  | "icon";

Accessibility

  • Use clear and descriptive labels for button text.
  • Preserve keyboard focus styles (focus-visible) for accessible navigation.
  • For icon-only buttons, provide an aria-label describing the action.
  • Avoid using Button with only an icon and no accessible text or label.

Design guidelines

  • Use default for the primary action on a page.
  • Use secondary or outline for secondary actions.
  • Use destructive only for actions that are dangerous or irreversible.
  • Prefer consistent button sizing within a view to preserve rhythm.