Design a button with every state in a live preview, then copy it as plain CSS, Tailwind CSS 4 classes or a Bootstrap 5 .btn variant. Start from one of 16 presets, such as ghost, outline, 3D pressed, neobrutalist, glass or a floating action button.

Hover, keyboard focus, pressed and disabled each have their own editor. While you work, the tool checks text contrast in each state, the focus ring against the page and the target size, and it can fix a failing check for you. The link keeps your work, so you can share it or come back to it.

CSS button generator Every state to CSS, Tailwind CSS 4 and Bootstrap 5

Presets

Preview

Page background
Show state

Live: hover, Tab to and press the preview button to try each state for real.

Accessibility checks

Checked against the light page.

  • Pass Text contrast at rest
  • Pass Text contrast on hover
  • Pass Text contrast when pressed
  • Pass Disabled state
  • Pass Focus ring against the page
  • Pass Target size
  • Pass Accessible name

Code

Used for the CSS and Bootstrap class, for example .btn-brand.

HTML

CSS with every state

The transition sits inside prefers-reduced-motion: no-preference, so state changes are instant for people who ask for less motion. The same class works on an <a href>; use aria-disabled="true" there instead of disabled.

Content

Icon position

An icon-only button has no visible text, so this becomes its aria-label, the name screen readers announce.

Text style

System font stacks only, so nothing is downloaded.

In hundredths of an em, so 5 means 0.05em.

Size and shape

Colours at rest

Fill

Frosts what is behind a see-through button (glass effect).

Hex colours, such as #297abe or #fff.

Shadow at rest

States

State to edit

Picking a state also shows it in the preview.

Hover :hover

Motion

Colours, border, shadow and movement ease between states. Gradients swap without easing, because browsers cannot animate background images. Set 0 for no transition.

How to use it

  1. Pick a preset that is close to the look you want, then set the button text, an optional icon and the font.
  2. Adjust padding, corner radius, border, the solid or gradient background, the text colour and the shadow at rest.
  3. Open the States card and edit the hover, focus, active and disabled looks. Choosing a state also shows it in the preview, and Live lets you hover, tab to and press the real button.
  4. Read the accessibility checks on the light and the dark page. Use Fix to bring a failing text contrast, focus ring or target size up to the threshold.
  5. Set a class name, choose the CSS, Tailwind 4 or Bootstrap 5 tab and copy the markup and code into your project.

Anatomy of a good button

A button is a label inside a padded box. The label should name the action with a verb, such as Save changes or Download report, so it still makes sense when it is read on its own by a screen reader or seen out of context.

Padding gives the button its size and should be larger left and right than top and bottom. A line height of about 1.25 keeps the text centred, and display: inline-flex with align-items: center lines an icon up with the text. Setting the icon size in em, such as 1.125em, makes it scale with the font size.

Colour, border and shadow show how important a button is. A page usually needs one filled primary button per section, with outline, ghost or link-style buttons for the secondary actions, so that the main action stands out.

Button states: hover, focus-visible, active and disabled

:hover reacts to a mouse pointer. It does not exist on touch screens, so it must never be the only way to reveal information. Tailwind CSS 4 applies hover: only on devices that can hover.

:focus-visible matches when the browser decides a focus ring is useful, which is mainly keyboard focus. Styling :focus-visible instead of :focus keeps the ring for keyboard users without showing it after every mouse click. An outline is the safest focus style, because it follows border-radius in current browsers and stays visible in Windows high-contrast modes, which remove box shadows.

:active matches while the button is being pressed by mouse, touch or the Space key. Hover is still true during a mouse press, so the active rule must override everything the hover rule changes. :disabled matches the disabled attribute. A disabled button cannot be focused or clicked, so explain elsewhere why an action is unavailable. On a link styled as a button, use aria-disabled="true" and stop the click in script instead.

Transitions between states should be short, about 100 to 250 milliseconds. Putting the transition inside @media (prefers-reduced-motion: no-preference) makes state changes instant for people who ask their system for less motion. Background images such as gradients cannot be animated, so they switch at once.

Accessible buttons: contrast, target size, focus and naming

WCAG 1.4.3 asks for a contrast of at least 4.5:1 between the label and the button background, or 3:1 for large text, which is 24px or 18.66px bold and larger. The rule applies in every interactive state, including hover and pressed. Icons that carry meaning on their own, as in an icon-only button, need 3:1 under WCAG 1.4.11. Disabled controls are exempt, but a label nobody can read is still a problem.

The focus indicator also needs 3:1 against the colours next to it, which is usually the page background when the outline has an offset. A ring of 2px or more is much easier to see than a 1px line.

WCAG 2.2 success criterion 2.5.8 sets a minimum target size of 24 by 24 CSS pixels. Apple and Google recommend about 44 or 48 pixels for touch, and WCAG 2.5.5 at level AAA asks for 44 by 44.

Use a button element for actions on the page and a link for navigation to another URL. Screen readers announce them differently, and keyboard users expect Space to press a button and Enter to follow a link. An icon-only button has no visible text, so it needs an aria-label, and the icon itself should carry aria-hidden="true".

Bootstrap 5 --bs-btn variables and Tailwind state variants

Since version 5.2, every Bootstrap button reads its colours and sizes from CSS variables set on .btn, such as --bs-btn-bg, --bs-btn-hover-bg, --bs-btn-active-bg, --bs-btn-disabled-bg, --bs-btn-padding-x and --bs-btn-border-radius. A custom variant only has to set these variables in a class such as .btn-brand and be used together with .btn.

The stock Bootstrap rules show the hover colours on :focus-visible and draw a box-shadow focus ring from --bs-btn-focus-box-shadow. The generated variant keeps the rest colours on keyboard focus, uses an outline for the ring and sets --bs-btn-disabled-opacity, which is 0.65 by default. Load it after bootstrap.min.css so it wins over the defaults.

In Tailwind CSS 4, each state is a prefix on a utility class: hover:bg-[#21669f], focus-visible:outline-2, active:translate-y-[1px] and disabled:opacity-60. Tailwind sorts these variants so that active wins over hover and disabled wins over both. motion-safe: adds the transition classes only when reduced motion is not requested, and arbitrary values in square brackets keep custom colours, shadows and gradients exact.

Frequently asked questions

What is the difference between :focus and :focus-visible?

:focus matches whenever an element has focus, including after a mouse click. :focus-visible matches only when the browser judges that a visible indicator helps, which is mainly keyboard and other non-pointer focus. Style the focus ring on :focus-visible so keyboard users always see it and mouse users are not shown a ring after every click.

How big should a button be?

WCAG 2.2 sets a minimum target size of 24 by 24 CSS pixels at level AA. For touch screens, 44 by 44 pixels is the common recommendation and the WCAG level AAA target. Padding of about 12px top and bottom with 16px text gives a 44px tall button.

Should I use a button or a link?

Use a button element for actions on the current page, such as submitting a form, opening a dialog or adding to a cart. Use an a element with an href for navigation to another page or URL. You can style either one to look like the other, but the element should match what it does.

How do I make a custom button colour in Bootstrap 5?

Create a class that sets the --bs-btn variables, such as --bs-btn-bg, --bs-btn-color, --bs-btn-hover-bg, --bs-btn-active-bg and --bs-btn-disabled-bg, then use it together with .btn, as in class="btn btn-brand". With Sass you can instead call the button-variant mixin before compiling Bootstrap.

Why does my button lose its focus outline?

The most common cause is a reset such as outline: none or outline: 0 on buttons or on :focus without a replacement style. Bootstrap also sets outline: 0 on .btn:focus-visible and uses a box shadow instead, which disappears in Windows high-contrast modes. Add an outline on :focus-visible with at least 3:1 contrast against the page.

More free tools