---
title: "JavaScript Button Group"
description: "The LemonadeJS Button Group block for JavaScript: Segmented button group. Contract-verified, framework-agnostic, zero dependencies, with a live example."
source: https://lemonadejs.com/docs/plugins/buttongroup/
---

<link rel="stylesheet" href="/v6/buttongroup.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined">

# JavaScript Button Group

`@lemonadejs/buttongroup` · ✓ 20 contract checks · framework-agnostic · zero dependencies

`<ButtonGroup />` — a fused row (or column) of buttons (LemonadeJS v6 block)

One block covering both plain action groups and toggle selection:
  selectable=''          plain action buttons — onclick(value, event)
  selectable='single'    exclusive selection — click selects, click
                         again deselects (value | null)
  selectable='multiple'  toggle set — the value is always an array

The selection follows the dropdown model, divisor-free:
  bind="${state}"  the live two-way selection (single value or array)
  external writes land silently; user toggles fire onchange (.set)

## Example

<!--example-->

```js
import { html } from 'lemonadejs';
import ButtonGroup from '@lemonadejs/buttongroup';

const App = (props, { state }) => {
    const period = state('month');
    const channels = state(['email']);

    return html`<div>
        <p>Report period</p>
        <${ButtonGroup} selectable="single" variant="outlined" bind="${period}"
            options="${[
                { value: 'week', label: 'Week' },
                { value: 'month', label: 'Month' },
                { value: 'quarter', label: 'Quarter' },
                { value: 'year', label: 'Year' },
            ]}" />
        <p>Notify me by</p>
        <${ButtonGroup} selectable="multiple" bind="${channels}"
            options="${[
                { value: 'email', label: 'Email' },
                { value: 'sms', label: 'SMS' },
                { value: 'slack', label: 'Slack' },
            ]}" />
        <p>Sending the <b>${period}</b> report via <b>${() => channels.value.join(', ') || 'nothing'}</b></p>
    </div>`;
};
```

## Installation

```bash
npm install @lemonadejs/buttongroup
```

```js
import Buttongroup from '@lemonadejs/buttongroup';
import '@lemonadejs/buttongroup/style.css';
```

The icons come from Google Material Symbols. Load the font once per page:

```html
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined">
```

Three deployment forms, one component:

```js
html`<${Buttongroup} />`                       // by value (no registration)
setComponents({ Buttongroup });               // then <Buttongroup /> by name anywhere
createWebComponent(Buttongroup);              // <lm-buttongroup> in plain HTML/any framework
```

## Props

Every declared prop arrives as a **live state** — pass a value for a snapshot or a
state for a two-way live wire. Attribute strings are coerced to the declared type.

| Prop | Type | Default | Description |
|---|---|---|---|
| `bind` | any | — | Two-way bound value. `.set()` fires `onchange`; plain assignment is silent. selection: single value, array when multiple (any) |
| `options` | array | — | { value, label, icon, disabled } or strings |
| `selectable` | string | `''` | '' action buttons | single | multiple |
| `variant` | string | `''` | '' contained | outlined | text |
| `color` | string | `''` | green | orange | red | purple |
| `size` | string | `''` | small | large (default in between) |
| `orientation` | string | `''` | '' horizontal | vertical |
| `disabled` | boolean | `false` | blocks the whole group (native) |
| `aria-label` | string | `''` |  |

## Events

All event names are lowercase (the platform convention — LJS-305 warns otherwise).

- `onchange` — (selection) on user toggles
- `onclick` — (value, event) in plain mode

## Styling

All classes follow the `lm-buttongroup-*` convention; visual variants are `data-*`
attributes on the root. Override freely — there is no styling engine to fight.

## Contract

The machine-readable schema ships with the package:

```js
import contract from '@lemonadejs/buttongroup/contract.json';
```

`verify.json` carries the conformance proof produced by `verify(Buttongroup)`.

Looking for the v5 plugin? See the [archived v5 documentation](/docs/v5/plugins/).