---
title: "JavaScript Button"
description: "The LemonadeJS Button block for JavaScript: Buttons in every variant and size. Contract-verified, framework-agnostic, zero dependencies, with a live example."
source: https://lemonadejs.com/docs/plugins/button/
---

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

`@lemonadejs/button` · ✓ 24 contract checks · framework-agnostic · zero dependencies

`<Button />` — a pressable action block (LemonadeJS v6)

Built on the v6 contract model: a real
`<button>` (native semantics, native disabled, native keyboard
activation) — or a real `<a>` when `href` is set. Three variants
(contained is the default), five colors, three sizes, an optional
material icon, and a loading state whose spinner replaces the content
while clicks are blocked. Ripple-free by design: hover/active/
focus-visible states live entirely in CSS.

Content: `label` for plain text, or children for anything richer —
both render inside the same button.

## Example

<!--example-->

```js
import { html } from 'lemonadejs';
import Button from '@lemonadejs/button';

const App = (props, { state }) => {
    const saving = state(false);
    const status = state('Draft not saved');

    const save = () => {
        saving.value = true;
        setTimeout(() => {
            saving.value = false;
            status.value = 'Saved at ' + new Date().toLocaleTimeString();
        }, 1200);
    };

    return html`<div>
        <div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">
            <${Button} label="Save changes" loading="${saving}" onclick="${save}" />
            <${Button} variant="outlined" label="Preview" onclick="${() => (status.value = 'Preview opened')}" />
            <${Button} variant="text" color="error" label="Discard" onclick="${() => (status.value = 'Draft discarded')}" />
            <${Button} color="success" size="small" label="Publish" disabled />
        </div>
        <p>${status}</p>
    </div>`;
};
```

## Installation

```bash
npm install @lemonadejs/button
```

```js
import Button from '@lemonadejs/button';
import '@lemonadejs/button/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`<${Button} />`                       // by value (no registration)
setComponents({ Button });               // then <Button /> by name anywhere
createWebComponent(Button);              // <lm-button> 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 |
|---|---|---|---|
| `label` | string | `''` | text content (children also supported) |
| `variant` | string | `''` | '' = contained | outlined | text |
| `color` | string | `''` | '' = primary | secondary | success | error | warning |
| `size` | string | `''` | small | large (default in between) |
| `disabled` | boolean | `false` | blocks interaction (native on `<button>`) |
| `loading` | boolean | `false` | spinner replaces the content; disabled while on |
| `fullwidth` | boolean | `false` | stretch to the container width |
| `href` | string | `''` | renders a real `<a>` instead of `<button>` |
| `type` | string | `''` | button type: submit | reset ('' = button) |
| `icon` | string | `''` | material icon name shown before the label |
| `aria-label` | string | `''` |  |

## Events

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

- `onclick` — fires on activation (never while disabled/loading)

## Styling

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

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

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