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

live
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

npm install @lemonadejs/button
import Button from '@lemonadejs/button';
import '@lemonadejs/button/style.css';

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

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

Three deployment forms, one component:

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.

PropTypeDefaultDescription
labelstring''text content (children also supported)
variantstring''” = contained
colorstring''” = primary
sizestring''small
disabledbooleanfalseblocks interaction (native on <button>)
loadingbooleanfalsespinner replaces the content; disabled while on
fullwidthbooleanfalsestretch to the container width
hrefstring''renders a real <a> instead of <button>
typestring''button type: submit
iconstring''material icon name shown before the label
aria-labelstring''

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:

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.