Toggle

Switches a setting on or off, applying the change immediately.

Installation

  1. Install the package.
npm install @hashintel/ds-components
  1. Import the component.
import { useState } from "react";

import { Toggle } from "@hashintel/ds-components";

export const PublicAccessSetting = () => {
  const [publicAccess, setPublicAccess] = useState(false);

  return (
    <Toggle
      labelOnText="Public access"
      value={publicAccess}
      onChange={setPublicAccess}
    />
  );
};

When to use

  • Do: Use Toggle for a binary setting that takes effect the moment it's flipped — enabling notifications, pausing a sync, making a workspace public.
  • Do: Use it in settings panels and option lists where each row is an independent on/off.
  • Do: Use it only where flipping back fully undoes the change — a toggle never asks for confirmation.

When not to use

  • Don't: Don't use Toggle for a choice that only applies when the form is saved — use Checkbox, which reads as deferred.
  • Don't: Don't use it to pick between two named alternatives, such as table and graph views — use SegmentedControl.
  • Don't: Don't use it to run an action or anything needing confirmation — use Button, with a confirming Dialog for irreversible changes.

Examples

Basic

Toggle is always controlled: value holds the on/off boolean and onChange receives the next one (see Installation for the state wiring). Apply the change as soon as onChange fires — a toggle promises immediate effect.

Disabled

A disabled toggle keeps its state visible but can't be flipped. Explain the constraint nearby — the dimmed control alone doesn't say why it's locked.

Invalid

Set invalid when validation rejects the current state — it draws a red ring and sets aria-invalid. Pair it with visible error text that says what's wrong.

Tones

tone colors the track when the toggle is on: neutral (default) for everyday settings, brand for primary features, success when on means healthy or complete.

Off tone

offTone colors the track when the toggle is off. The default neutral reads as a plain "off"; error flags an off state that needs attention, such as a protection left disabled. Don't signal it with color alone — say why nearby.

Sizes

md is the default; the label text scales with the control. Use xxs–sm in dense chrome such as table rows and panel headers, lg for prominent settings.

Labels

labelOnText renders after the control, on the on side; labelOffText renders before it, on the off side. Use either one as the setting's label, or both to caption the two poles — both stay visible whichever way the switch sits.

In forms

Inside Form.Field, leave the label props off — the field's label is wired to the hidden input automatically. When on, the hidden native checkbox submits "on" under name; required blocks native submission while off.

import { useState } from "react";

import { Form, Toggle } from "@hashintel/ds-components";

export const InferenceSettingRow = () => {
  const [aiInference, setAiInference] = useState(true);

  return (
    <Form.Field layout="inline" label="Enable AI inference">
      <Toggle
        name="aiInference"
        value={aiInference}
        onChange={setAiInference}
      />
    </Form.Field>
  );
};

Behavior

  • The whole component renders as one <label> wrapping a hidden native checkbox, so clicking the track or either label toggles. Don't nest it inside another label or interactive element.

Content

  • Label the setting, not the state: "Public access", not "On" or "Enabled". Keep the wording identical whichever way the switch sits.
  • Use a short verb or noun phrase — 1–4 words, sentence case, no punctuation: "Autosave", "Sync entity changes".
  • In general phrase for the on state: "Show archived entities", rather than "Hide archived entities". Switching off a negative is a double negative.
  • Reserve the two-label form for true poles ("Off"/"On"); two named alternatives belong in SegmentedControl.

Accessibility

Toggle implements the WAI-ARIA switch pattern.

What Toggle provides

  • A visually hidden native <input type="checkbox"> inside a <label>.
  • labelOnText/labelOffText render as label parts that name the input.

What you must do

  • Give every toggle a name: labelOnText/labelOffText, a wrapping Form.Field label, or aria-label when the visible label lives elsewhere.
  • Don't rely on offTone="error" color alone — pair it with text that explains the problem.
  • Prefer explaining a constraint over disabled — a disabled toggle has reduced contrast and doesn't say why it's locked.

API reference

PropTypeDescription
value
boolean
onChange
(value: boolean) => void
tone
"neutral" |⁠ "brand" |⁠ "success"
default: "neutral"
offTone
"neutral" |⁠ "error"
default: "neutral"
labelOnText
string
labelOffText
string
name
string
onFocus
FocusEventHandler<HTMLInputElement>
onBlur
FocusEventHandler<HTMLInputElement>
invalid
boolean
autoFocus
boolean |⁠ "never"
disabled
boolean
required
boolean
size
"xxs" |⁠ "xs" |⁠ "sm" |⁠ "md" |⁠ "lg"
default: "md"

Was this page helpful?

On this page