# Toggle (/docs/toggle)





## API Reference [#api-reference]

<BaseUIReference href="https://base-ui.com/react/components/toggle" />

## Basic [#basic]

<Preview cssProperties="togglePlaygroundCssProperties">
  <ToggleExample />

  <Preview.Code>
    {`
          import { StarIcon, Toggle } from "moduix";

          export function ToggleDemo() {
            return (
              <Toggle defaultPressed>
                <StarIcon />
                Favorite
              </Toggle>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSSProperties>
    {(context) => <ToggleCssPropertiesPanel {...context} />}
  </Preview.CSSProperties>

  <Preview.CSSPlayground>
    {(context) => <ToggleCssPlaygroundPanel {...context} />}
  </Preview.CSSPlayground>
</Preview>

## Anatomy [#anatomy]

`Toggle` is composed as a single interactive root that represents a pressed/unpressed state.

```text
Toggle
└─ label and/or icon content
```

| Part     | Role                                                                    |
| -------- | ----------------------------------------------------------------------- |
| `Toggle` | Two-state button root that handles pressed, focus, and disabled states. |

## Composition [#composition]

Use `Toggle` props such as `pressed`, `defaultPressed`, `onPressedChange`, `disabled`, `render`,
`className`, and `style`.

There are no hidden service slots such as `Positioner`, `Backdrop`, or `Viewport` in this
component, so `className` is the customization entry point. It supports the same state callback
form as Base UI and is merged with moduix styles.

## Examples [#examples]

### Variants [#variants]

Use `variant` to match the visual weight of the toggle to the surrounding toolbar or form.

<Preview>
  <ToggleVariantsExample />

  <Preview.Code>
    {`
          import { Toggle } from "moduix";
          import styles from "./toggle.module.css";

          export function ToggleVariantsDemo() {
            return (
              <div className={styles.row}>
                <Toggle>Default</Toggle>
                <Toggle variant="outline">Outline</Toggle>
                <Toggle variant="ghost">Ghost</Toggle>
                <Toggle defaultPressed>Pressed</Toggle>
              </div>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .row {
            display: flex;
            flex-wrap: wrap;
            align-items: center;
            justify-content: center;
            gap: var(--spacing-3);
          }
        `}
  </Preview.CSS>
</Preview>

### Sizes [#sizes]

Use text sizes for labeled toggles and icon sizes for compact controls.

<Preview>
  <ToggleSizesExample />

  <Preview.Code>
    {`
          import { Toggle } from "moduix";
          import styles from "./toggle.module.css";

          export function ToggleSizesDemo() {
            return (
              <div className={styles.row}>
                <Toggle size="xs">Extra-small</Toggle>
                <Toggle size="sm">Small</Toggle>
                <Toggle size="md">Medium</Toggle>
                <Toggle size="lg">Large</Toggle>
              </div>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .row {
            display: flex;
            flex-wrap: wrap;
            align-items: center;
            justify-content: center;
            gap: var(--spacing-3);
          }
        `}
  </Preview.CSS>
</Preview>

### Icons [#icons]

Pass icons as children. Icon-only toggles must include an accessible label.

<Preview>
  <ToggleIconExample />

  <Preview.Code>
    {`
          import { BellIcon, CheckSmallIcon, StarIcon, Toggle } from "moduix";
          import styles from "./toggle.module.css";

          export function ToggleIconsDemo() {
            return (
              <div className={styles.row}>
                <Toggle variant="outline">
                  <BellIcon />
                  Alerts
                </Toggle>
                <Toggle size="icon-md" variant="outline" aria-label="Favorites">
                  <StarIcon />
                </Toggle>
                <Toggle size="icon-md" variant="ghost" aria-label="Enabled" defaultPressed>
                  <CheckSmallIcon />
                </Toggle>
              </div>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .row {
            display: flex;
            flex-wrap: wrap;
            align-items: center;
            justify-content: center;
            gap: var(--spacing-3);
          }
        `}
  </Preview.CSS>
</Preview>

### Disabled [#disabled]

Use `disabled` to prevent interaction while preserving the current pressed state.

<Preview>
  <ToggleDisabledExample />

  <Preview.Code>
    {`
          import { Toggle } from "moduix";
          import styles from "./toggle.module.css";

          export function DisabledToggleDemo() {
            return (
              <div className={styles.row}>
                <Toggle disabled>Disabled</Toggle>
                <Toggle defaultPressed disabled>
                  Pressed
                </Toggle>
              </div>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .row {
            display: flex;
            flex-wrap: wrap;
            align-items: center;
            justify-content: center;
            gap: var(--spacing-3);
          }
        `}
  </Preview.CSS>
</Preview>

### Controlled [#controlled]

Control `pressed` from React state when the toggle needs to coordinate with other UI.

<Preview>
  <ControlledToggleExample />

  <Preview.Code>
    {`
          import { BellIcon, Toggle } from "moduix";
          import { useState } from "react";
          import styles from "./toggle.module.css";

          export function ControlledToggleDemo() {
            const [pressed, setPressed] = useState(false);

            return (
              <div className={styles.stack}>
                <Toggle pressed={pressed} onPressedChange={setPressed}>
                  <BellIcon />
                  {pressed ? "Notifications on" : "Notifications off"}
                </Toggle>
                <span className={styles.hint}>Current value: {String(pressed)}</span>
              </div>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .stack {
            display: flex;
            flex-direction: column;
            align-items: flex-start;
            gap: var(--spacing-3);
          }

          .hint {
            color: var(--color-muted-foreground);
            font-size: var(--text-xs);
            line-height: var(--line-height-text-xs);
          }
        `}
  </Preview.CSS>
</Preview>

### Render Callback [#render-callback]

Use the `render` callback when the icon or rendered element should depend on the pressed state.

<Preview>
  <ToggleRenderCallbackExample />

  <Preview.Code>
    {`
          import { Toggle } from "moduix";
          import styles from "./toggle.module.css";

          export function ToggleRenderCallbackDemo() {
            return (
              <Toggle
                aria-label="Save article"
                size="icon-md"
                variant="outline"
                render={(buttonProps, state) => (
                  <button type="button" {...buttonProps}>
                    {state.pressed ? (
                      <BookmarkFilledIcon className={styles.customIcon} />
                    ) : (
                      <BookmarkIcon className={styles.customIcon} />
                    )}
                  </button>
                )}
              />
            );
          }

          function BookmarkIcon(props) {
            return (
              <svg viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false" {...props}>
                <path
                  d="M4.5 2.75h7v10.5L8 11l-3.5 2.25V2.75Z"
                  stroke="currentColor"
                  strokeWidth="1.5"
                  strokeLinejoin="round"
                />
              </svg>
            );
          }

          function BookmarkFilledIcon(props) {
            return (
              <svg viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" focusable="false" {...props}>
                <path d="M4 2.75A.75.75 0 0 1 4.75 2h6.5a.75.75 0 0 1 .75.75v10.5a.75.75 0 0 1-1.16.63L8 12.03l-2.84 1.85A.75.75 0 0 1 4 13.25V2.75Z" />
              </svg>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .customIcon {
            width: 1rem;
            height: 1rem;
          }
        `}
  </Preview.CSS>
</Preview>

### Custom Styles [#custom-styles]

Pass `className` when styling the toggle with CSS Modules, Tailwind CSS, or CSS-in-JS.

<Preview>
  <CustomStylesToggleExample />

  <Preview.Code>
    {`
          import { CheckSmallIcon, Toggle } from "moduix";
          import styles from "./toggle.module.css";

          export function CustomStylesToggleDemo() {
            return (
              <Toggle className={styles.customToggle} variant="outline" defaultPressed>
                <CheckSmallIcon />
                Styled with className
              </Toggle>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .customToggle {
            --toggle-outline-bg: color-mix(in oklab, var(--color-primary) 8%, transparent);
            --toggle-outline-bg-hover: color-mix(in oklab, var(--color-primary) 14%, transparent);
            --toggle-outline-bg-active: color-mix(in oklab, var(--color-primary) 18%, transparent);
            --toggle-outline-border-color: color-mix(in oklab, var(--color-primary) 45%, var(--color-border));
            --toggle-outline-color: var(--color-primary);
            --toggle-outline-bg-pressed: var(--color-primary);
            --toggle-outline-border-color-pressed: var(--color-primary);
            --toggle-outline-color-pressed: var(--color-primary-foreground);
          }
        `}
  </Preview.CSS>
</Preview>
