CSS Button Generator

Free tool No sign-up
Presets29 buttons · scroll for more
Primary
Outlined
Material
iOS
Trendy
Status
Specialty
State
Shadow
Advanced
Preview on:
Show state:
Text4.47:1Fail
On background4.28:1AA
Try a variationClick to adopt
Export
Colors:
.btn {
  background: #6366f1;
  color: #ffffff;
  border: none;
  border-radius: 10px;
  padding: 12px 20px;
  font-size: 15px;
  font-weight: 600;
  box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.18);
  cursor: pointer;
  transition: all 180ms ease;
}

.btn:hover {
  background: #5358e6;
  box-shadow: 0px 8px 18px 0px rgba(0, 0, 0, 0.25);
  transform: translateY(-1px) scale(1);
}

.btn:active {
  background: #4a4fd6;
  box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.22);
  transform: translateY(0px) scale(0.98);
}

.btn:disabled {
  background: #3a3a44;
  color: #888888;
  cursor: not-allowed;
  box-shadow: none;
}

.btn:focus-visible {
  outline: 3px solid #a78bfa;
  outline-offset: 2px;
}

/* Respect users who prefer reduced motion */
@media (prefers-reduced-motion: reduce) {
  .btn { transition: none; }
}

/* Loading state — add the .btn--loading class to the button */
/* (also set the disabled attribute + aria-busy="true" for a11y) */
.btn--loading {
  background: #5358e6;
  color: rgba(255,255,255,0.8);
  cursor: wait;
  pointer-events: none;
}
.btn--loading::before {
  content: "";
  display: inline-block;
  width: 14px;
  height: 14px;
  margin-right: 8px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  vertical-align: middle;
  animation: btn-spin 0.7s linear infinite;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }

About this generator

Most CSS button generators give you a static button — set the colors, copy the code, ship it. Then the first developer who hovers over it discovers the hover state was an afterthought, the focus ring is missing, and the disabled style looks identical to enabled. This generator was built to fix exactly that gap.

All six interactive states — default, hover, active, focus, disabled, loading — live in one editor with tabs. Each state has its own complete style set; you can override only what changes from default and let the rest inherit, or pin a totally distinct treatment per state. The live preview lets you hover, click, and tab through the button so you can see every state actually fire, not just imagine what it would look like.

Three more differences worth calling out. Background-aware preview — pick the actual page background your button will sit on (white, dark, brand, gradient, mesh) so you can see whether the contrast holds. WCAG contrast scoring — live AA / AAA ratio for both text-on-button and button-on-page-background, so contrast-failing combos get flagged before you ship. Framework export — copy plain CSS, SCSS variables, Tailwind classes, React inline-style, or Vue scoped CSS. The output includes a proper :focus-visible ring and a prefers-reduced-motion guard automatically.

Permalink: every adjustment encodes into the URL hash, so you can bookmark a tuned button or send it to a teammate. No login, no watermark, no paywall. Free and MIT-licensed.

?

How to use

01
Edit the default state
Start on the Default tab. Set background, text color, radius, padding, font size, and shadow. The live preview updates as you drag any slider.
02
Switch to Hover / Active / Focus tabs
Each interactive state has its own complete style set. Override only what changes — leave the rest to inherit from Default. Most competitors skip this entirely; users get a button that "looks great until you hover."
03
Pick the right page background
Click a preset (White, Dark, Mesh) or pick a custom color. The button renders ON your actual page background — no more "looked great in the void" surprises.
04
Check WCAG contrast
The contrast panel shows text-on-button and button-on-page-background ratios. Aim for AA (4.5:1) minimum. AAA (7:1) for body text on critical CTAs.
05
Try a variation
Click any of the algorithmic remixes (Darker / Flat / Squared / Pill / Ghost) to instantly adopt that variant as your new default.
06
Export to your stack
Pick CSS, SCSS, Tailwind, React inline-style, or Vue scoped. Copy with one click. Output includes all interactive states, a focus ring, and a prefers-reduced-motion fallback.
</>

Common button snippets

All states
.btn {
  background: #6366f1;
  color: #fff;
  /* ...default styles */
}
.btn:hover { background: #5358e6; transform: translateY(-1px); }
.btn:active { background: #4a4fd6; transform: translateY(0); }
.btn:focus-visible { outline: 3px solid #a78bfa; outline-offset: 2px; }
.btn:disabled { opacity: 0.6; cursor: not-allowed; }
Reduced motion
@media (prefers-reduced-motion: reduce) {
  .btn { transition: none; }
}
Accessible markup
<!-- Correct: disabled = both visual + semantic -->
<button disabled aria-disabled="true">Saving…</button>

<!-- Correct: loading = visual spinner + busy semantic -->
<button aria-busy="true" disabled>
  <span class="spinner" aria-hidden="true"></span>
  Loading…
</button>
Tailwind
<button class="bg-indigo-500 hover:bg-indigo-600 active:bg-indigo-700
  text-white font-semibold px-5 py-3 rounded-lg
  transition-all duration-200
  focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2
  disabled:opacity-60 disabled:cursor-not-allowed
  motion-reduce:transition-none">
  Get started
</button>

Browser support

Every property the generator emits — including box-shadow, transitions, transform, focus-visible, prefers-reduced-motion — is supported in every evergreen browser. Safe to ship anywhere.

Chrome v1+
Safari v1+
Firefox v1+
Edge v12+

Pro tips

01
A button without hover state feels broken
Even a tiny color shift (5-10% darker) on hover signals to the user that the element is interactive. The 50ms-200ms transition between default and hover is the difference between "looks like a link" and "looks like a button."
02
Always add a focus indicator
WCAG 2.4.7 requires a visible focus state for keyboard users. The default browser ring is ugly but functional — don't set <code>outline: none</code> without replacing it with your own focus ring. The Focus tab generates an accessible <code>outline</code> by default.
03
Disabled buttons need visual AND semantic markers
A disabled button should look different (gray, reduced opacity) AND have the <code>disabled</code> HTML attribute. Screen readers announce "dimmed" or "unavailable" when the attribute is present, regardless of styling.
04
Don't pulse a primary CTA — it screams
Animated, pulsing buttons cross from "energetic" to "needy" fast. Subtle hover lift (translateY -1 to -2px) reads as polished. Continuous loops scream "click me!" and erode trust.
05
Respect prefers-reduced-motion
Vestibular-sensitive users disable motion in their OS. Always wrap hover transitions in a <code>@media (prefers-reduced-motion: reduce)</code> guard that removes the transition. The generator outputs this guard automatically.
06
Loading state needs pointer-events: none
A loading button must NOT accept clicks — otherwise users double-submit. Combine the visual spinner with <code>pointer-events: none</code> + <code>aria-busy="true"</code> on the element. The generator's Loading tab outputs this combination.

Frequently asked questions

Why does this generator have hover, active, focus, disabled, and loading tabs when most CSS button generators don’t?

Because a button isn’t one style — it’s six. A real button has to look right when the user hovers (hover), when they click and hold (active), when they tab to it with the keyboard (focus), when it’s not interactive (disabled), and when an action is in progress (loading). Generators that only edit the default state produce buttons that break in production. This generator’s state-tab editor is the single biggest difference between us and every other free button generator in this category — including Tailwind UI’s static button library, shadcn/ui’s pre-styled components, and the older generators like CSS3 Button Generator or BestCSSButtonGenerator that ship a single static state.

How does the Tailwind button export compare to writing utility classes by hand or using Tailwind UI?

The Tailwind export emits the exact utility classes (including arbitrary-value square-bracket syntax for any non-token values like bg-[#6366f1]) for default, hover, active, disabled, focus-visible, and motion-reduce states. We deliberately use arbitrary values instead of trying to map to Tailwind’s named tokens (indigo-500, etc.) because the alternative produces guesswork; honest hex values are more accurate. For users coming from Tailwind UI ($300+/year component license), shadcn/ui (free React components), HeadlessUI, or Radix Primitives, this generator gives you the styling layer they assume you already have. If you want the values pulled into your tailwind.config.js as tokens, the SCSS export gives you that token list directly. Tailwind v3 and v4 both consume the output identically — no migration needed.

Why bother with the WCAG contrast checker — isn’t 4.5:1 enough?

4.5:1 (WCAG AA) is the minimum legal threshold for body text under accessibility regulations including the EU EAA (European Accessibility Act, enforceable June 2025), US Section 508, Canada ACA, and dozens of other jurisdictions. AAA (7:1) is recommended for critical CTAs because: (1) the AA threshold was calibrated for screens 20 years ago — modern OLED and bright-environment usage is harsher, (2) older users and users with low vision benefit substantially from higher ratios, (3) brand-color drift in implementation eats into the margin over time. If your product faces accessibility compliance scrutiny — government work, EU sales, enterprise B2B, healthcare, finance — using a generator that flags contrast failures BEFORE you ship is worth the 30 seconds. Tools like axe DevTools, Lighthouse, WAVE, and Deque axe-core catch these in audit but only after you’ve already pushed; this catches them at design time. The CSS export also includes the :focus-visible ring and prefers-reduced-motion guards that WCAG 2.4.7 and 2.3.3 require.

Why does the generator output a prefers-reduced-motion media query?

Roughly 35% of adults experience some level of motion sensitivity — vestibular disorders, migraine triggers, or simply preferring less visual noise. Users with these issues set prefers-reduced-motion: reduce in their OS (macOS Accessibility, Windows Animation, iOS / Android). A button with a transition: all 200ms that snaps to its hover state instead of fading is the polite default. The generator wraps the transition rule in a @media (prefers-reduced-motion: reduce) block that sets the button’s transition to none block automatically — you don’t have to remember to add it. This is one line of CSS that prevents migraine triggers in your users; it’s worth shipping.

Can I save the button to my project as a CSS class, or do I have to copy it every time?

Both work. Quick path: copy the generated CSS to your project’s stylesheet under the class name .btn (which the export uses) — it’s a complete production-ready snippet. Tokenized path: copy the SCSS export instead, which extracts the colors, padding, radius, and shadow as SCSS variables you can reuse across components. Tailwind path: copy the class string into your component template; for an extracted version, define a @layer components block in your CSS file containing .btn with @apply directives for the utility list.

How is this different from Tailwind UI, shadcn/ui, Material UI, or Chakra UI buttons?

Tailwind UI ($300+/year), shadcn/ui (free, React + Radix), Material UI / MUI (~95kb bundle), Chakra UI, Ant Design, Mantine, and HeadlessUI all ship pre-styled button COMPONENTS — pick from primary / secondary / outline / ghost variants, accept the design, copy. This generator is a button STYLE EDITOR — start from a primary or pick your own colors, customize every dimension, see all 6 states live, export to whichever stack you use. Use component libraries when you want a complete design system in 30 seconds. Use this generator when you want fine control over a specific button’s look (brand-specific accent, exact corner radius, custom hover lift) or when you’re building your own design system from scratch and need the source CSS to inform your token decisions. The Tailwind export means you can keep your component-library workflow and just generate the styling for a button that doesn’t match any of the library’s defaults.

Why is the URL changing as I drag sliders?

Every adjustment is encoded into the URL hash (the part after #) so the entire state machine is shareable. Bookmark a tuned button → reopen the URL → button is exactly where you left it. Send the URL to a colleague → they see your exact configuration. No accounts, no servers, no logins. The hash is base64-encoded JSON; you can inspect it in DevTools if you’re curious.

Will more features be added?

Yes. The current release is “Tier 1” of the planned feature set: multi-state editor + framework export + WCAG checker + variant compare + background-aware preview. Planned for v1.1: OKLCH/P3 color output, modern CSS features (accent-color, @property, color-mix, light-dark), preset library of 30 hand-curated production buttons (Stripe, Linear, GitHub, Vercel patterns), history with undo/redo, save-to-localStorage personal library. Planned for v1.2: AI-suggested variants. Track the roadmap in our repo’s TODO.md.

?

Frequently asked questions

01

Why does this generator have hover, active, focus, disabled, and loading tabs when most CSS button generators don't?

Because a button isn't one style — it's six. A real button has to look right when the user hovers (hover), when they click and hold (active), when they tab to it with the keyboard (focus), when it's not interactive (disabled), and when an action is in progress (loading). Generators that only edit the default state produce buttons that break in production. This generator's state-tab editor is the single biggest difference between us and every other free button generator in this category — including Tailwind UI's static button library, shadcn's pre-styled components, and the older generators like CSS3 Button Generator or BestCSSButtonGenerator that ship a single static state.

02

How does the Tailwind button export compare to writing utility classes by hand or using Tailwind UI?

The Tailwind export emits the exact utility classes — including arbitrary-value square-bracket syntax for non-token values like bg-[#6366f1] — for default, hover, active, disabled, focus-visible, and motion-reduce states. We deliberately use arbitrary values instead of trying to map to Tailwind's named tokens (indigo-500, etc.) because the alternative produces guesswork; honest hex values are more accurate. For users coming from Tailwind UI ($300+/year for component licenses), shadcn/ui (free React components), HeadlessUI, or Radix Primitives, this generator gives you the styling layer they assume you already have. Tailwind v3 and v4 both consume the output identically — no migration needed.

03

Why bother with the WCAG contrast checker — isn't 4.5:1 enough?

4.5:1 (WCAG AA) is the minimum legal threshold for body text under EU EAA accessibility regulations, US Section 508, Canadian ACA, and dozens of other jurisdictions. AAA (7:1) is recommended for critical CTAs because (1) the AA threshold was calibrated for screens 20 years ago and modern OLED + bright-environment usage is harsher, (2) older users and users with low vision benefit substantially from higher ratios, (3) brand-color drift in implementation eats into the margin over time. If your product faces accessibility compliance scrutiny — government work, EU sales, enterprise B2B, healthcare, finance — using a generator that flags contrast failures before you ship is worth the 30 seconds to check. Tools like axe-core, Lighthouse, and WAVE catch these in audit but only after you've already pushed; this catches them at design time.

04

Why does the generator output a prefers-reduced-motion media query automatically?

Roughly 35% of adults experience some level of motion sensitivity — vestibular disorders, migraine triggers, or simply preferring less visual noise. Users with these issues set prefers-reduced-motion: reduce in their OS (macOS Accessibility, Windows Animation, iOS Reduce Motion, Android Remove Animations). A button with a 200ms transition that snaps to its hover state instead of fading is the polite default. The generator wraps the transition rule in a prefers-reduced-motion block that sets the button's transition to none automatically — you don't have to remember. WCAG 2.3.3 (Animation from Interactions) explicitly recommends this; the generator ships it by default so your CTAs never trigger a migraine in your users.

05

Can I save the button to my project as a CSS class, or do I have to copy it every time?

Both work. Quick path: copy the generated CSS to your project's stylesheet under the .btn class (which the export uses) — it's a complete production-ready snippet you can drop in. Tokenized path: copy the SCSS export instead, which extracts the colors, padding, radius, and shadow as SCSS variables you can reuse across components. Tailwind path: copy the class string into your component template; for an extracted version, define a @layer components block with .btn @apply for the utility list. The URL hash also encodes the entire button state so you can bookmark it and return later — useful for design system documentation pages where you want every component spec to be reproducible by URL.

06

How is this different from Tailwind UI buttons or shadcn/ui button components?

Tailwind UI ($300+/year) and shadcn (free) ship pre-styled button COMPONENTS — pick from primary / secondary / outline / ghost, accept the design, copy. This generator is a button STYLE EDITOR — start from a primary or pick your own colors, customize every dimension, see all 6 states live, export to whichever stack you use. Use Tailwind UI or shadcn when you want a complete design system in 30 seconds. Use this generator when you want fine control over a specific button's look (brand-specific accent, exact corner radius, custom hover lift) or when you're building your own design system from scratch and need the source CSS to inform your token decisions. Same applies for Material UI, Chakra UI, Ant Design, Mantine — those are component libraries; this is the layer beneath them.

07

Why is the URL changing as I drag sliders?

Every adjustment is encoded into the URL hash (the part after #) so the entire state machine is shareable. Bookmark a tuned button, reopen the URL, the button is exactly where you left it. Send the URL to a colleague, they see your exact configuration. No accounts, no servers, no logins. The hash is base64-encoded JSON; you can inspect it in DevTools if you're curious. This is especially useful for design system docs — link to the canonical primary button URL from your docs page and the live editor opens with your design system's exact spec preloaded.

08

What about converting CSS button hover effects to React Native or Flutter?

This generator targets web (CSS, Tailwind, SCSS, React DOM, Vue). For React Native, hover doesn't exist as a concept — touch platforms use onPressIn / onPressOut for the equivalent of :active, and tvOS / web-via-react-native uses focusable. You can adapt the active-state styles directly into a Pressable component. For Flutter, the closest equivalent is MaterialButton's overlayColor + animationDuration; copy the hover-state colors into your ButtonStyle. The web-first approach here is deliberate — the 40K monthly searches for css button generator are 95% web developers; the cross-platform niches are better served by Expo's design tokens or Flutter's official Material specifications.

09

Will more features be added?

Yes. The current release is Tier 1 of the planned feature set: multi-state editor + framework export (CSS, SCSS, Tailwind, React, Vue) + WCAG contrast checker + variant compare + background-aware preview. Planned for v1.1: OKLCH and Display-P3 color output (the 2026 default for designers), modern CSS feature flags (accent-color, color-mix, light-dark, @property for animated custom properties), preset library of 30 hand-curated production buttons (Stripe, Linear, GitHub, Vercel, Notion patterns), history with undo/redo, save-to-localStorage personal library. Planned for v1.2: AI-suggested variants (Claude Haiku-powered), PNG/SVG export, embed iframe code. Track the roadmap in our public TODO.md.

Search CodeFronts

Loading…