Components / Inputs & Forms

Button

Primary actions, secondary actions, and destructive operations.

Variants

Sizes

States

Source ButtonDemo.tsx

The exact code behind the live demo above. Fetch it raw at /components/source/button.txt.

import React from "react";

function Section({ title, children }: { title: string; children: React.ReactNode }) {
  return (
    <div className="mb-8">
      <h3 className="text-sm font-bold text-[var(--flux-heading)] mb-3">{title}</h3>
      <div className="p-6 rounded border border-[var(--flux-grey-100)] bg-[var(--flux-surface)]">
        {children}
      </div>
    </div>
  );
}

function Spinner() {
  return (
    <svg
      className="animate-spin h-4 w-4"
      viewBox="0 0 24 24"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
    >
      <circle
        className="opacity-25"
        cx="12"
        cy="12"
        r="10"
        stroke="currentColor"
        strokeWidth="4"
      />
      <path
        className="opacity-75"
        fill="currentColor"
        d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"
      />
    </svg>
  );
}

const base =
  "font-bold transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-[var(--flux-primary-300)]";

const r = "rounded-[4px]";

export default function ButtonDemo() {
  return (
    <div>
      <Section title="Variants">
        <div className="flex flex-wrap gap-3">
          <button
            className={`${base} ${r} bg-[var(--flux-primary-600)] hover:bg-[var(--flux-primary-500)] active:bg-[var(--flux-primary-700)] text-white text-sm px-4 py-2`}
          >
            Primary
          </button>
          <button
            className={`${base} ${r} bg-[var(--flux-grey-100)] hover:bg-[var(--flux-grey-200)] active:bg-[var(--flux-grey-100)] text-[var(--flux-black)] text-sm px-4 py-2`}
          >
            Secondary
          </button>
          <button
            className={`${base} ${r} border border-[var(--flux-primary-600)] text-[var(--flux-primary-600)] bg-transparent hover:bg-[var(--flux-primary-50)] active:bg-[var(--flux-primary-100)] text-sm px-4 py-2`}
          >
            Outline
          </button>
          <button
            className={`${base} ${r} bg-transparent text-[var(--flux-primary-600)] hover:bg-[var(--flux-primary-50)] active:bg-[var(--flux-primary-100)] text-sm px-4 py-2`}
          >
            Ghost
          </button>
          <button
            className={`${base} ${r} bg-[var(--flux-error)] hover:opacity-90 active:opacity-100 text-white text-sm px-4 py-2`}
          >
            Danger
          </button>
        </div>
      </Section>

      <Section title="Sizes">
        <div className="flex flex-wrap items-center gap-3">
          <button
            className={`${base} ${r} bg-[var(--flux-primary-600)] hover:bg-[var(--flux-primary-500)] active:bg-[var(--flux-primary-700)] text-white text-xs px-3 py-1.5`}
          >
            Small
          </button>
          <button
            className={`${base} ${r} bg-[var(--flux-primary-600)] hover:bg-[var(--flux-primary-500)] active:bg-[var(--flux-primary-700)] text-white text-sm px-4 py-2`}
          >
            Medium
          </button>
          <button
            className={`${base} ${r} bg-[var(--flux-primary-600)] hover:bg-[var(--flux-primary-500)] active:bg-[var(--flux-primary-700)] text-white text-base px-6 py-2.5`}
          >
            Large
          </button>
        </div>
      </Section>

      <Section title="States">
        <div className="flex flex-wrap items-center gap-3">
          <button
            disabled
            className={`${base} ${r} bg-[var(--flux-primary-600)] text-white text-sm px-4 py-2 opacity-50 cursor-not-allowed`}
          >
            Disabled
          </button>
          <button
            className={`${base} ${r} bg-[var(--flux-primary-600)] hover:bg-[var(--flux-primary-500)] text-white text-sm px-4 py-2 inline-flex items-center gap-2`}
          >
            <Spinner />
            Loading
          </button>
        </div>
      </Section>
    </div>
  );
}