---
title: "JavaScript Toggle"
description: "The LemonadeJS Toggle block for JavaScript: Toggle button with icon support. Contract-verified, framework-agnostic, zero dependencies, with a live example."
source: https://lemonadejs.com/docs/plugins/toggle/
---

<link rel="stylesheet" href="/v6/toggle.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 Toggle

`@lemonadejs/toggle` · ✓ 16 contract checks · framework-agnostic · zero dependencies

`<Toggle />` — a pressable toggle button (LemonadeJS v6 block)

Full behavioral parity with the v5 plugin: a single on/off button built on
a hidden <input type="checkbox"> with an optional material icon and text
label (v5 props: text, icon, value, name, disabled, onchange). Distinct
from `<Switch />`: this looks like a button that stays pressed.

bind vs checked (the v6 split of v5's `value`):
  bind="${state}"  the live two-way pressed state (wins when present)
  checked          the INITIAL state when unbound

## Example

<!--example-->

```js
import { html } from 'lemonadejs';
import Toggle from '@lemonadejs/toggle';

const App = (props, { state }) => {
    const mic = state(true);
    const camera = state(false);

    return html`<div>
        <${Toggle} bind="${mic}" icon="mic" text="Microphone" />
        <${Toggle} bind="${camera}" icon="videocam" text="Camera" />
        <${Toggle} icon="screen_share" text="Share screen" disabled />
        <p>Joining the call with
            <b>${() => (mic.value ? 'mic on' : 'mic muted')}</b> and
            <b>${() => (camera.value ? 'camera on' : 'camera off')}</b></p>
    </div>`;
};
```

## Installation

```bash
npm install @lemonadejs/toggle
```

```js
import Toggle from '@lemonadejs/toggle';
import '@lemonadejs/toggle/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`<${Toggle} />`                       // by value (no registration)
setComponents({ Toggle });               // then <Toggle /> by name anywhere
createWebComponent(Toggle);              // <lm-toggle> 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` | boolean | — | Two-way bound value. `.set()` fires `onchange`; plain assignment is silent. two-way pressed state (v5: value) |
| `checked` | boolean | `false` | initial state when unbound |
| `text` | string | `''` | label text displayed next to the toggle |
| `icon` | string | `''` | material icon name (e.g. 'mic', 'videocam') |
| `name` | string | `''` | form identification name |
| `disabled` | boolean | `false` | blocks interaction (native) |
| `aria-label` | string | `''` |  |

## Events

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

- `onchange` — fires on user-initiated changes

## API

```js
import { ref } from 'lemonadejs';
const toggle = ref();
html`<${Toggle} ref="${toggle}" />`;
// toggle.current.toggle(...)
```

- `toggle()`

## Styling

All classes follow the `lm-toggle-*` 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/toggle/contract.json';
```

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

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