Toggle

A two-state button that stays pressed or unpressed, for formatting, view and filter actions.

<tp-toggle>
Toggle
Default density Compact density Restart from the initial state Show the copyable source

Usage

A Toggle is an action with a remembered state, exposed as a button with aria-pressed. It does not submit a form value; use Checkbox for a Boolean field and Radio Group for a single choice. To coordinate several Toggles, put them in a Toggle Group.

Grouped Toggles derive pressed state from the Group; use group.setValue() instead of item.setPressed(). Group variant and size take precedence, and removing an item restores its independently authored configuration.

Variants and sizes

Variants and sizes
Default density Compact density Restart from the initial state Show the copyable source
Ghost Outline
Extra small Small Default Large

Pressed paint stays distinct while hovered, so the state reads the same whether or not the pointer is over it.

The host sizes to its content. A host given an inline size, or stretched by a column or grid container, draws a Control of the same width, as Button does. Its height is the height of its size, whatever the line height around it.

icon-xs, icon-sm, icon and icon-lg make square Toggles at the heights of xs, sm, the default and lg, with no inline padding, also inside a joined Toggle group. Use them for Toggles that hold only an icon, and name each with aria-label.

Icon sizes
Default density Compact density Restart from the initial state Show the copyable source

Icons

Compose a tp-icon in the default slot. Icons are decorative, so an icon-only Toggle needs an aria-label; with visible text the label is enough. data-icon="inline-start" tightens the edge padding beside the icon. Toggle has no separate icon property. An explicit tp-icon.size remains authoritative; an unspecified icon uses the control’s size context.

Icon and label
Default density Compact density Restart from the initial state Show the copyable source
Saved

Artwork that follows the state

To swap artwork with the pressed state, such as an outlined bookmark that fills in, render the content from the state through partContracts. The toggle-content part’s content receives the committed state, and html from lit builds the template.

Pressed artwork
Default density Compact density Restart from the initial state Show the copyable source

Beside Buttons

Toggles share the Button’s variants and sizes, so a Toggle and a Button of the same size line up in a toolbar. Use the Button for a one-off action and the Toggle for a state that stays on.

With Buttons
Default density Compact density Restart from the initial state Show the copyable source
Insert link Spell check Insert link Spell check

Listening to changes

Every press proposes the inverse state through a cancelable tp-value-change. Read event.detail.value to react, or call event.preventDefault() to keep the current state. A disabled or canceled request does not change committed state.

The first update fixes controlled/uncontrolled ownership. A controlled callback accepts or rewrites by assigning pressed. Without an owner return, the committed state stays unchanged.

Change events
Default density Compact density Restart from the initial state Show the copyable source
Mute notifications Notifications are on

Disabled

Disabled
Default density Compact density Restart from the initial state Show the copyable source
Archived Pinned

A disabled Toggle leaves the tab order and ignores presses; its pressed state is still shown.

Inside a Toolbar

Register a Toggle with a ToolbarController as a button item. The toolbar then owns its tab stop: the Toggle joins the toolbar’s single arrow-key sequence, while its pressed state, value and aria-pressed stay its own. A disabled Toggle, or any Toggle of a disabled toolbar, stays a focusable stop with aria-disabled="true" unless the item is registered with focusableWhenDisabled: false; pointer presses, Enter and Space leave its state unchanged. The toolbar’s disabled state never becomes the Toggle’s own disabled or toggleDisabled. Disposing the registration restores the standalone tab order.

import { ToolbarController } from '@tweakpad/ui'; import '@tweakpad/ui/register'; // Existing markup: // <div id="format" aria-label="Formatting"> // <tp-button id="clear">Clear</tp-button> // <tp-toggle id="wrap">Wrap lines</tp-toggle> // </div> await customElements.whenDefined('tp-button'); await customElements.whenDefined('tp-toggle'); const toolbar = new ToolbarController(document.getElementById('format')!); toolbar.registerItem(document.getElementById('clear')!, { kind: 'button' }); toolbar.registerItem(document.getElementById('wrap')!, { kind: 'button' });

A Toggle group inside a toolbar registers its own Toggles; do not register them yourself.

API Reference

Every element also accepts motion-policy.

Attributes

AttributePropertyTypeDefaultDescriptionpressedpressedboolean—Whether the Toggle is pressed. Set it to own the state: presses then propose changes and the Toggle shows only what you assign.default-presseddefaultPressedboolean | undefined—The pressed state at first render, when the page does not own pressed.aria-labelariaLabelstring | null—The accessible name of a Toggle that shows only an Icon.native-actionnativeActionbooleantrueRenders the control as a native button; turn it off only when a part contract supplies another element.variantvariant'ghost' | 'outline'—The paint: ghost shows a fill only while pressed or hovered, outline adds a border for a Toggle that stands alone.sizesizeToggleSize—The height and padding, matching the Button sizes; the icon-* sizes make a square Toggle for an Icon alone.

Properties

PropertyTypeDefaultDescriptiononPressedChange((event: TpValueChangeEvent<boolean>) => void) | undefined—Called with each proposed state before it commits; assign pressed to accept it or cancel the event to reject it.selectionOwnerToggleSelectionOwner | null—The Toggle group that owns this Toggle's state, if any; set by the group itself.controlElementread-onlyHTMLElement | null—The inner button that carries the pressed state and receives focus.toggleDisabledread-onlyboolean—Whether the Toggle is disabled, by itself or by its Toggle group.

Events

EventTypeDescriptiontp-value-changeTpValueChangeEvent<boolean>Cancelable proposal of the inverse pressed state on each press of a standalone Toggle; detail.value, detail.previousValue and the detail.reason.

Methods

MethodReturnsDescriptionsetPressed(pressed, reason, event?)voidProposes a new pressed state as if the user had made it, notifying listeners first; a grouped Toggle ignores it, since its group owns the value.

Slots

SlotDescriptiondefaultThe label: text, an Icon, or both. Mark a leading or trailing Icon with data-icon="inline-start" or data-icon="inline-end" to tighten the padding on that edge.

CSS parts

PartDescription::part(toggle)The native button that carries the pressed state.::part(toggle-content)The label inside the button; its part contract can render content from the pressed state.

Components, widgets and patterns that use this one.

Show more