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.
Presets
Preview
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.
Button with utility classes
The first lines style the button at rest; each line after that is one state: hover:, focus-visible:, active: and disabled:. motion-safe: adds the transition only when reduced motion is not requested. Tailwind 4 applies hover: only on devices that can hover.
HTML
Custom .btn variant
Load this after Bootstrap 5.3. The --bs-btn-* variables drive the rest, hover, active and disabled colours of the stock .btn rules. Bootstrap shows hover colours on keyboard focus, so the variant restores the rest colours there and swaps the focus shadow for an outline.
Content
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
Frosts what is behind a see-through button (glass effect).
Hex colours, such as #297abe or #fff.
Shadow at rest
States
Hover :hover
Keyboard focus :focus-visible
The ring is an outline, so it follows the corner radius and still shows in Windows high-contrast modes, where box shadows are removed. A positive offset puts a gap of page colour between the button and the ring.
Pressed :active
Disabled :disabled
Disabled buttons lose the shadow and movement and show a not-allowed cursor. WCAG does not require contrast for inactive controls, but people still need to read the label.
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
- Pick a preset that is close to the look you want, then set the button text, an optional icon and the font.
- Adjust padding, corner radius, border, the solid or gradient background, the text colour and the shadow at rest.
- 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.
- 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.
- 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
- CSS Gradient Generator – Linear, radial and conic gradients with draggable colour stops and OKLCH blending.
- Glassmorphism Generator – Frosted glass with a live contrast check against the busiest part of your background.
- SVG Wave & Divider Generator – Waves, peaks and curves between sections, as inline SVG with CSS, Tailwind and Bootstrap code.
- CSS Box Shadow Generator – Layered, smooth and neumorphic shadows with a live preview.
- CSS Clip-path & Blob Generator – Drag polygon points or roll organic blobs, then copy clip-path, border-radius or SVG.
- Colour Palette Generator – Harmonies and OKLCH tonal scales with a contrast grid, exported as CSS, Tailwind @theme or Bootstrap.