An accessible CSS button generator with every state
The CSS Button Generator lets you design a button the way users will meet it: at rest, under the mouse, focused from the keyboard, while being pressed and when disabled. Set the label, font, padding, corner radius, border, solid or gradient background and shadow, then switch between states to fine-tune each one while the preview stays in that state.
Most button generators stop at a hover colour. This one also checks accessibility as you work, using the same maths as our Contrast Checker: text contrast for the default, hover and pressed backgrounds, whether keyboard focus is visible and strong enough, and the button’s measured size against the 24 × 24 pixel minimum target in WCAG 2.2.
When it looks and tests right, copy a clean HTML snippet and CSS — optionally written with custom properties so the states only swap variables. It all happens in your browser.
How to use the CSS Button Generator
- Start from a preset: Primary, Ghost, Pill, 3D, Neumorphic, Gradient or Soft.
- Type the button text and class name, then adjust font, size, weight, padding, radius and border.
- Under “Colour and depth” choose a solid, gradient or transparent background, the text colour, a shadow and the page colour behind the button.
- Pick Hover, Focus, Active or Disabled under “States” and edit that state; choose Default to try the button live with the mouse and the Tab key.
- Fix anything marked “Fail” in the accessibility checks.
- Copy the HTML and CSS. Tick “Use CSS custom properties” if you theme with variables.
CSS Button Generator features
Five real states
Hover and active rules use :not(:disabled), focus uses :focus-visible, and disabled gets reduced opacity and a not-allowed cursor.
Live WCAG 2.2 checks
Contrast per state (the lowest point of a gradient is used), focus ring visibility and contrast, and the rendered size in CSS pixels.
Seven presets
Primary, ghost, pill, 3D with a pressable edge, neumorphic, gradient and soft — each passing AA text contrast out of the box.
Preview equals output
The preview is styled by the very CSS you copy, with selectors renamed, so there are no surprises in your project.
Motion-aware
Transitions list only the properties that change and switch off under prefers-reduced-motion.
What the three accessibility checks mean
Disabled buttons are exempt from the contrast minimum because they cannot be used, but people still need to read them — avoid opacity below about 40%.
- Text contrast (WCAG 1.4.3, AA): the ratio of the lighter to the darker colour’s relative luminance, each plus 0.05. Button text needs 4.5:1, or 3:1 when it counts as large — 24px, or 18.66px bold. White on #6d28d9 is 7.1:1; #777 grey on white is 4.47:1 and fails, while #767676 is 4.54:1 and passes. With a gradient, the tool samples it and reports the worst point.
- Focus indicator (2.4.7 and 1.4.11, AA): keyboard users must see which control has focus, and the ring needs 3:1 against the colours next to it — the page when it is offset outwards, the button when inset. A ring 2px or thicker also suits the AAA Focus Appearance criterion (2.4.13).
- Target size (2.5.8, AA, new in WCAG 2.2): pointer targets should be at least 24 × 24 CSS pixels, unless enough spacing surrounds a smaller one. 44 × 44 is the stricter AAA level (2.5.5). The size shown is measured from the rendered preview.
Worked example: the Primary preset
With the Primary preset the rule for the hover state comes out as .my-button:hover:not(:disabled) { background: #5b21b6; box-shadow: …; transform: translateY(-1px); }. White text on #5b21b6 measures 8.98:1, and on the pressed colour #4c1d95 it is 10.95:1, so every state passes AA. The 3px #6d28d9 focus ring sits 2px outside the button and contrasts 7.1:1 with the white page. At 16px text with 12px vertical padding, the button is 44px tall — comfortably above both target-size levels.
Because :active also matches :hover, the active rule resets the hover lift with transform: none (or moves the button down for the 3D preset), giving a satisfying press.
Tips for buttons that work everywhere
- Use a real
<button type="button">for actions and an<a>for navigation; the CSS works on both. - Never remove the focus outline without replacing it.
:focus-visibleshows the ring for keyboard users without leaving one after a mouse click. - Gradient backgrounds do not animate with
transition; the hover change is instant unless you fade a pseudo-element instead. - Ghost buttons depend on the page colour behind them. Change “Page background” to your real background before trusting the result.
- Fine-tune shadows in the Box Shadow Generator, gradients in the Gradient Generator and borders in the CSS Border Generator.
CSS Button Generator FAQ
How do I create a button in HTML and CSS?
Write <button type="button" class="my-button">Get started</button> and style the class with padding, colours, border-radius and a hover rule. This CSS button generator writes both parts, including focus, active and disabled states.
What is the difference between :focus and :focus-visible?
:focus matches whenever the button has focus, including after a mouse click. :focus-visible matches only when the browser decides a focus indicator is helpful — mainly keyboard use — so you can show a strong ring without bothering mouse users.What contrast ratio does button text need?
At least 4.5:1 against the button background under WCAG AA, or 3:1 for large text (24px, or 18.66px and bold). The checks above recalculate this for the default, hover and pressed colours.
How big should a button be?
WCAG 2.2 asks for at least 24 × 24 CSS pixels (2.5.8, AA). Apple and Android guidelines and the AAA criterion recommend about 44 × 44 for touch screens.
Why does my hover effect apply to disabled buttons?
A plain :hover rule matches disabled buttons too. Write :hover:not(:disabled), as the generated CSS does, so a disabled button stays still.
How do I make a 3D button press effect?
Give the button a hard shadow below it, such as box-shadow: 0 4px 0 #b08619, then on :active move it down with transform: translateY(4px) and shrink the shadow to zero. The 3D preset does exactly this.