ToggleButton
An interactive toggle control for on/off or selected/unselected states
Usage
import { ToggleButton } from '@lenso/ui';"use client";
import { Heart } from "@gravity-ui/icons";import { ToggleButton } from "@lenso/ui";
export function Basic() { return ( <ToggleButton> <ToggleButton.Icon> <Heart /> </ToggleButton.Icon> Like </ToggleButton> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Examples
Variants
"use client";// Adapted from HeroUI v3.2.6 (e385ac2), Apache-2.0.import { Heart } from "@gravity-ui/icons";import { ToggleButton } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { styles } from "./source.stylex";export function Variants() { return ( <div {...stylex.props(styles.row)}> <ToggleButton> <ToggleButton.Icon> <Heart /> </ToggleButton.Icon> Default </ToggleButton> <ToggleButton variant="ghost"> <ToggleButton.Icon> <Heart /> </ToggleButton.Icon> Ghost </ToggleButton> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Icon Only
"use client";// Adapted from HeroUI v3.2.6 (e385ac2), Apache-2.0.import { Bookmark, Heart } from "@gravity-ui/icons";import { ToggleButton } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { styles } from "./source.stylex";export function IconOnly() { return ( <div {...stylex.props(styles.row)}> <ToggleButton isIconOnly aria-label="Like"> <ToggleButton.Icon> <Heart /> </ToggleButton.Icon> </ToggleButton> <ToggleButton isIconOnly aria-label="Bookmark" variant="ghost"> <ToggleButton.Icon> <Bookmark /> </ToggleButton.Icon> </ToggleButton> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Sizes
"use client";// Adapted from HeroUI v3.2.6 (e385ac2), Apache-2.0.import { Heart } from "@gravity-ui/icons";import { ToggleButton } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { styles } from "./source.stylex";export function Sizes() { return ( <div {...stylex.props(styles.column)}> <div {...stylex.props(styles.row)}> {(["sm", "md", "lg"] as const).map((size, index) => ( <ToggleButton key={size} size={size}> <ToggleButton.Icon> <Heart /> </ToggleButton.Icon> {["Small", "Medium", "Large"][index]} </ToggleButton> ))} </div> <div {...stylex.props(styles.row)}> {(["sm", "md", "lg"] as const).map((size) => ( <ToggleButton key={size} isIconOnly aria-label="Like" size={size}> <ToggleButton.Icon> <Heart /> </ToggleButton.Icon> </ToggleButton> ))} </div> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Disabled
"use client";// Adapted from HeroUI v3.2.6 (e385ac2), Apache-2.0.import { Heart, HeartFill } from "@gravity-ui/icons";import { ToggleButton } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { styles } from "./source.stylex";export function Disabled() { return ( <div {...stylex.props(styles.row)}> <ToggleButton disabled> <ToggleButton.Icon> <Heart /> </ToggleButton.Icon> Like </ToggleButton> <ToggleButton defaultPressed disabled> <ToggleButton.Icon> <HeartFill /> </ToggleButton.Icon> Like </ToggleButton> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Controlled
"use client";// Adapted from HeroUI v3.2.6 (e385ac2), Apache-2.0.import { Heart, HeartFill } from "@gravity-ui/icons";import { ToggleButton } from "@lenso/ui";import { useState } from "react";import * as stylex from "@stylexjs/stylex";import { styles } from "./source.stylex";export function Controlled() { const [selected, setSelected] = useState(false); return ( <div {...stylex.props(styles.controlled)}> <ToggleButton pressed={selected} onPressedChange={setSelected}> <ToggleButton.Icon>{selected ? <HeartFill /> : <Heart />}</ToggleButton.Icon> {selected ? "Liked" : "Like"} </ToggleButton> <p {...stylex.props(styles.muted)}> Status:{" "} <span {...stylex.props(styles.medium)}>{selected ? "Selected" : "Not selected"}</span> </p> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Customization
Tailwind CSS
"use client";// Adapted from HeroUI v3.2.6 (e385ac2), Apache-2.0.import { Heart } from "@gravity-ui/icons";import { ToggleButton } from "@lenso/ui";import { styles } from "./source.stylex";export function CustomStyles() { return ( <ToggleButton xstyle={styles.custom}> <ToggleButton.Icon xstyle={styles.icon}> <Heart /> </ToggleButton.Icon> Save article </ToggleButton> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
Global CSS
To customize the ToggleButton component classes, you can use the @layer components directive.
Learn more.
@layer components { .toggle-button { @apply bg-purple-500 text-white; }
.toggle-button--icon-only { @apply rounded-lg; }}Styling Reference
HeroUI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.
CSS Classes
The ToggleButton component uses these CSS classes (View source styles):
Base & Size Classes [!toc]
.toggle-button- Base toggle button styles.toggle-button--sm- Small size variant.toggle-button--md- Medium size variant (default).toggle-button--lg- Large size variant
Variant Classes [!toc]
.toggle-button--default- Default variant with filled background.toggle-button--ghost- Ghost variant with transparent background
Modifier Classes [!toc]
.toggle-button--icon-only- Icon-only toggle button.toggle-button--icon-only.toggle-button--sm- Small icon-only.toggle-button--icon-only.toggle-button--lg- Large icon-only
Interactive States
The toggle button supports both CSS pseudo-classes and data attributes for flexibility:
- Selected:
[data-selected="true"](accent background and foreground) - Hover:
:hoveror[data-hovered="true"] - Active/Pressed:
:activeor[data-pressed="true"](includes scale transform) - Focus:
:focus-visibleor[data-focus-visible="true"](shows focus ring) - Disabled:
:disabledor[aria-disabled="true"](reduced opacity, no pointer events)
API Reference
ToggleButton
Inherits from React Aria ToggleButton.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'default' | 'ghost' | 'default' | Visual style variant |
size | 'sm' | 'md' | 'lg' | 'md' | Size of the toggle button |
isIconOnly | boolean | false | Whether the button contains only an icon |
isSelected | boolean | - | Controlled selected state |
defaultSelected | boolean | false | Default selected state (uncontrolled) |
isDisabled | boolean | false | Whether the toggle button is disabled |
onChange | (isSelected: boolean) => void | - | Handler called when selection changes |
onPress | (e: PressEvent) => void | - | Handler called when the button is pressed |
children | React.ReactNode | (values: ToggleButtonRenderProps) => React.ReactNode | - | Button content or render prop |
Render Props
When using the render prop pattern, these values are provided:
| Prop | Type | Description |
|---|---|---|
isSelected | boolean | Whether the button is currently selected |
isPressed | boolean | Whether the button is currently pressed |
isHovered | boolean | Whether the button is hovered |
isFocused | boolean | Whether the button is focused |
isFocusVisible | boolean | Whether the button should show focus indicator |
isDisabled | boolean | Whether the button is disabled |