Skip to content

Buttons & Selection

Buttons

Elements that trigger an immediate action. Styles are reset to the browser's default style.

html
<button style="all: revert">Click</button>

Predefines roles

Buttons can have predefined actions for forms.

html
<div style="display: flex; gap: 1ex">
<button type="submit" style="all: revert">Submit</button>
<button type="reset" style="all: revert">Reset</button>
</div>
css
.fancy-button {
  padding: 0.3em 0.6em;
  font-size: 1rem;
  font-weight: 600;
  color: white;
  background-color: #3b82f6;
  border: none;
  border-radius: 0.5em;
  cursor: pointer;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
  transition: background-color 0.2s ease, transform 0.1s ease;

  &:hover {
    background-color: #2563eb;
  }
  
  &:active {
    transform: scale(0.97);
  }

  &:focus-visible {
    outline: 2px solid #93c5fd;
    outline-offset: 2px;
  }
}

Styling buttons

html
<button class="fancy-button">Styled button</button>
css
.fancy-button {
  padding: 0.3em 0.6em;
  font-size: 1rem;
  font-weight: 600;
  color: white;
  background-color: #3b82f6;
  border: none;
  border-radius: 0.5em;
  cursor: pointer;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
  transition: background-color 0.2s ease, transform 0.1s ease;

  &:hover {
    background-color: #2563eb;
  }
  
  &:active {
    transform: scale(0.97);
  }

  &:focus-visible {
    outline: 2px solid #93c5fd;
    outline-offset: 2px;
  }
}

Button with icon

You can put arbitrary HTML elements inside the button, such das icons. Make sure to adjust the spacing, for example using flex-box.

Here, an icon from an icon font is used, see Icons.

html
<button class="fancy-button with-icon">
  <span class="material-icons">send</span>
  Send
</button>
css
.with-icon {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
}

Different visual roles

html
<div style="display: flex; gap: 1ex">
<button class="fancy-button primary">Primary</button>
<button class="fancy-button secondary">Secondary</button>
<button class="fancy-button danger">Danger</button>
</div>
css
.fancy-button {
  &.secondary {
    background-color: #6b7280;
  }

  &.secondary:hover {
    background-color: #4b5563;
  }

  &.danger {
    background-color: #ef4444;
  }

  &.danger:hover {
    background-color: #dc2626;
  }
}

Split button with menu

A split button with menu can be implemented using two buttons styled in a way so that they form one visual entity.

html
<div class="split-button" role="group">
  <button class="main-action">Save</button>
  <button class="dropdown-toggle"
          aria-haspopup="menu"
          aria-expanded="false"
          aria-controls="save-options"
          aria-label="More save options"
          id="save-toggle"
          popovertarget="save-options">
    <span class="material-icons" aria-hidden="true">arrow_drop_down</span>
  </button>
</div>
<ul id="save-options" role="menu" popover anchor="save-toggle">
  <li role="none"><button type="button" role="menuitem">Save as draft</button></li>
  <li role="none"><button type="button" role="menuitem">Export...</button></li>
</ul>
css
.split-button {
  display: inline-flex;

  button {
    border: none;
    padding: 0.5em 1em;
    background: #3b82f6;
    color: white;
    cursor: pointer;
    transition: background 0.2s ease;
  
    &:hover {
      background: #2563eb;
    }
  
    &:first-child {
      border-radius: 0.5em 0 0 0.5em;
      padding-right: 0.5em;
    }
  
    &:last-child {
      border-radius: 0 0.5em 0.5em 0;
      padding-left: 0.5em;
      display: grid;
      place-items: center;
      anchor-name: --anchor_1;
    }
  }
}

ul[role="menu"] {
  position-anchor: --anchor_1;
  top: anchor(bottom);
  right: anchor(right);
  left: auto;
  bottom: auto;

  min-width: 12rem;
  margin-top: .25rem;
  padding: .25rem;
  
  border: 1px solid #ccc;
  background: white;
  border-radius: .5rem;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);

  li {
    margin: 0;
    padding: 0;

    button {
      width: 100%;
      text-align: left;
      padding: .5rem;
      border-radius: .4rem;

      &:hover,
      &:focus-visible {
        background: #f3f4f6;
      }
    }
  }
}

WARNING

The mechanism for the popup menu is currently only available in Chrome from version 125

Toolbar button

html
<button class="toolbar-button" aria-label="Edit">
  <span class="material-icons">edit</span>
</button>
css

.toolbar-button {
  width: 2.5em;
  height: 2.5em;
  border: none;
  background: none;
  cursor: pointer;
  border-radius: 0.4em;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.2s ease;
}

.toolbar-button:hover {
  background-color: #e5e7eb;
}

.toolbar-button:focus-visible {
  outline: 2px solid #60a5fa;
  outline-offset: 2px;
}

.material-icons {
  font-size: 1.4em;
}

Toggle Controls (On/Off, Many-of-Many)

Allow toggling of states or selecting multiple options:

html
<input type="checkbox" id="terms">
<label for="terms">Accept terms</label>

HTML label element ensures that the label is also clickable

Styling checkbox

Change tickbox using emoji

Icon only: Ex: Photoshop layer view

Animations for transitioning

  • Up down
  • Only down
    • Maybe without clip but fade?
  • Same for horizontal
  • 90 degree rotate with fade
  • Cube transition
  • Zoom in/out
  • Flip
  • Fade Without clip:
  • Zoom out fade / reveal

Lottie animation?

  • Opening Eye?

Mobile style switcher

You can do it with CSS [1], but there is also a native version on the horizon [2]. WebKit already has support [3]

Exclusive Selection (One-of-Many)

Choose one option among several:

  • <input type="radio">
  • <select> (single mode)
  • Tab group (via ARIA)
html
<input type="radio" name="color" value="red" checked> Red
<input type="radio" name="color" value="blue"> Blue

Multi-Selection

Choose multiple options from a list:

  • <select multiple>
  • Checkbox groups
html
<select multiple>
  <option>Apple</option>
  <option>Banana</option>
  <option>Cherry</option>
</select>

Accessibility Considerations

  • Use semantic HTML whenever possible
  • Provide visible labels or use aria-label
  • Maintain keyboard operability (tab, space, enter)
  • Avoid div-based buttons unless roles and interactions are fully replicated
  • Icons – for visual enhancement of controls

References


  1. https://www.w3schools.com/howto/howto_css_switch.asp ↩︎

  2. Native switch at WHATWG: Proposal and Bugreport ↩︎

  3. Native switcher in Webkit: Blog article ↩︎