or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

tessl/npm-radix-ui--react-switch

A two-state control used to toggle between checked and unchecked states

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@radix-ui/react-switch@1.2.x

To install, run

npx @tessl/cli install tessl/npm-radix-ui--react-switch@1.2.0

0

# Radix UI React Switch

1

2

@radix-ui/react-switch is a TypeScript React component library that provides an accessible, unstyled switch component. It implements a two-state control for toggling between checked and unchecked states with proper ARIA attributes, keyboard navigation, and form integration.

3

4

## Package Information

5

6

- **Package Name**: @radix-ui/react-switch

7

- **Package Type**: npm

8

- **Language**: TypeScript

9

- **Installation**: `npm install @radix-ui/react-switch`

10

11

## Core Imports

12

13

```typescript

14

import * as Switch from "@radix-ui/react-switch";

15

```

16

17

Or with named imports:

18

19

```typescript

20

import { Switch, SwitchThumb, Root, Thumb } from "@radix-ui/react-switch";

21

```

22

23

For CommonJS:

24

25

```javascript

26

const Switch = require("@radix-ui/react-switch");

27

```

28

29

## Basic Usage

30

31

```typescript

32

import * as Switch from "@radix-ui/react-switch";

33

import { useState } from "react";

34

35

function SwitchDemo() {

36

const [checked, setChecked] = useState(false);

37

38

return (

39

<form>

40

<div style={{ display: "flex", alignItems: "center" }}>

41

<label

42

className="Label"

43

htmlFor="airplane-mode"

44

style={{ paddingRight: 15 }}

45

>

46

Airplane mode

47

</label>

48

<Switch.Root

49

className="SwitchRoot"

50

id="airplane-mode"

51

checked={checked}

52

onCheckedChange={setChecked}

53

>

54

<Switch.Thumb className="SwitchThumb" />

55

</Switch.Root>

56

</div>

57

</form>

58

);

59

}

60

```

61

62

## Architecture

63

64

The component follows Radix UI's compound component pattern with two main parts:

65

66

- **Switch/Root**: The main interactive button element that handles state and accessibility

67

- **SwitchThumb/Thumb**: The visual indicator that shows the current state

68

69

The component supports both controlled and uncontrolled usage patterns, integrates seamlessly with HTML forms, and provides proper ARIA attributes for screen readers.

70

71

## Capabilities

72

73

### Switch Component

74

75

The main switch component that renders as an accessible button with switch role.

76

77

```typescript { .api }

78

/**

79

* Base primitive components from @radix-ui/react-primitive

80

*/

81

type PrimitivePropsWithRef<E extends React.ElementType> = React.ComponentPropsWithRef<E> & {

82

asChild?: boolean;

83

};

84

85

interface PrimitiveForwardRefComponent<E extends React.ElementType>

86

extends React.ForwardRefExoticComponent<PrimitivePropsWithRef<E>> {}

87

88

declare const Primitive: {

89

button: PrimitiveForwardRefComponent<"button">;

90

span: PrimitiveForwardRefComponent<"span">;

91

input: PrimitiveForwardRefComponent<"input">;

92

};

93

94

/**

95

* Element type for Switch component

96

*/

97

type SwitchElement = React.ComponentRef<typeof Primitive.button>;

98

99

/**

100

* Props type for Primitive.button

101

*/

102

type PrimitiveButtonProps = React.ComponentPropsWithoutRef<typeof Primitive.button>;

103

104

/**

105

* Main switch component that renders as a button with switch role

106

*/

107

const Switch: React.ForwardRefExoticComponent<

108

SwitchProps & React.RefAttributes<SwitchElement>

109

>;

110

111

/**

112

* Alternative export name for the Switch component

113

*/

114

const Root: React.ForwardRefExoticComponent<

115

SwitchProps & React.RefAttributes<SwitchElement>

116

>;

117

118

interface SwitchProps extends PrimitiveButtonProps {

119

/** The controlled checked state of the switch */

120

checked?: boolean;

121

/** The checked state of the switch when it is initially rendered. Use when you do not need to control its checked state */

122

defaultChecked?: boolean;

123

/** When true, indicates that the user must check the switch before the owning form can be submitted */

124

required?: boolean;

125

/** The name of the switch. Submitted with its owning form as part of a name/value pair */

126

name?: string;

127

/** The value given as data when submitted with a `name`. Defaults to "on" */

128

value?: string;

129

/** Associates the control with a form element */

130

form?: string;

131

/** When true, prevents the user from interacting with the switch */

132

disabled?: boolean;

133

/** Event handler called when the checked state of the switch changes */

134

onCheckedChange?(checked: boolean): void;

135

}

136

```

137

138

**Key Features:**

139

- Supports both controlled (`checked` + `onCheckedChange`) and uncontrolled (`defaultChecked`) patterns

140

- Automatically integrates with HTML forms through hidden input element with `name` and `value` props

141

- Provides proper ARIA attributes (`role="switch"`, `aria-checked`, `aria-required`)

142

- Handles keyboard navigation (Space and Enter keys toggle state)

143

- Includes form integration with proper event bubbling and validation support

144

- Uses internal `SwitchBubbleInput` component for seamless form submission

145

146

**Data Attributes:**

147

- `data-state`: "checked" | "unchecked" - Current switch state

148

- `data-disabled`: Present when disabled

149

150

### Switch Thumb Component

151

152

The visual indicator component that displays the current state of the switch.

153

154

```typescript { .api }

155

/**

156

* Element type for SwitchThumb component

157

*/

158

type SwitchThumbElement = React.ComponentRef<typeof Primitive.span>;

159

160

/**

161

* Props type for Primitive.span

162

*/

163

type PrimitiveSpanProps = React.ComponentPropsWithoutRef<typeof Primitive.span>;

164

165

/**

166

* Visual thumb/handle component that indicates the switch state

167

*/

168

const SwitchThumb: React.ForwardRefExoticComponent<

169

SwitchThumbProps & React.RefAttributes<SwitchThumbElement>

170

>;

171

172

/**

173

* Alternative export name for the SwitchThumb component

174

*/

175

const Thumb: React.ForwardRefExoticComponent<

176

SwitchThumbProps & React.RefAttributes<SwitchThumbElement>

177

>;

178

179

interface SwitchThumbProps extends PrimitiveSpanProps {}

180

```

181

182

**Key Features:**

183

- Automatically receives state from parent Switch component through context

184

- Renders as a span element for styling flexibility

185

- Inherits data attributes from Switch context for consistent styling

186

187

**Data Attributes:**

188

- `data-state`: "checked" | "unchecked" - Current switch state

189

- `data-disabled`: Present when disabled

190

191

### Context Utilities

192

193

Utility function for creating component scopes when composing multiple switch instances.

194

195

```typescript { .api }

196

/**

197

* Scope type for context management

198

*/

199

type Scope<C = any> = { [scopeName: string]: React.Context<C>[] } | undefined;

200

201

/**

202

* Hook type returned by createSwitchScope

203

*/

204

type ScopeHook = (scope: Scope) => { [__scopeSwitch: string]: Scope };

205

206

/**

207

* Creates a scope for switch components to avoid context conflicts

208

* Used when composing multiple switch instances or building compound components

209

*/

210

function createSwitchScope(): ScopeHook;

211

```

212

213

**Usage:**

214

```typescript

215

import { createSwitchScope } from "@radix-ui/react-switch";

216

217

// Create a scoped context for this specific switch instance

218

const useScope = createSwitchScope();

219

220

function MyComponent() {

221

const scope = useScope();

222

223

return (

224

<Switch.Root {...scope}>

225

<Switch.Thumb />

226

</Switch.Root>

227

);

228

}

229

```

230

231

## Usage Examples

232

233

### Controlled Switch

234

235

```typescript

236

import * as Switch from "@radix-ui/react-switch";

237

import { useState } from "react";

238

239

function ControlledSwitch() {

240

const [isChecked, setIsChecked] = useState(false);

241

242

return (

243

<Switch.Root checked={isChecked} onCheckedChange={setIsChecked}>

244

<Switch.Thumb />

245

</Switch.Root>

246

);

247

}

248

```

249

250

### Uncontrolled Switch

251

252

```typescript

253

import * as Switch from "@radix-ui/react-switch";

254

255

function UncontrolledSwitch() {

256

return (

257

<Switch.Root defaultChecked={true}>

258

<Switch.Thumb />

259

</Switch.Root>

260

);

261

}

262

```

263

264

### Form Integration

265

266

```typescript

267

import * as Switch from "@radix-ui/react-switch";

268

269

function FormSwitch() {

270

return (

271

<form onSubmit={(e) => {

272

e.preventDefault();

273

const formData = new FormData(e.currentTarget);

274

console.log(formData.get("notifications")); // "on" or null

275

}}>

276

<div style={{ display: "flex", alignItems: "center" }}>

277

<label htmlFor="notifications-switch" style={{ paddingRight: 15 }}>

278

Enable notifications

279

</label>

280

<Switch.Root

281

id="notifications-switch"

282

name="notifications"

283

value="on"

284

defaultChecked={false}

285

>

286

<Switch.Thumb />

287

</Switch.Root>

288

</div>

289

<button type="submit">Submit</button>

290

</form>

291

);

292

}

293

```

294

295

**Form Integration Details:**

296

- The `name` prop determines the form field name in the submitted data

297

- The `value` prop sets the value when checked (defaults to "on")

298

- When unchecked, the field is not included in form submission (standard HTML behavior)

299

- A hidden input element is automatically created to handle form submission

300

301

### Disabled Switch

302

303

```typescript

304

import * as Switch from "@radix-ui/react-switch";

305

306

function DisabledSwitch() {

307

return (

308

<div style={{ display: "flex", alignItems: "center" }}>

309

<label htmlFor="disabled-switch" style={{ paddingRight: 15 }}>

310

Cannot change this

311

</label>

312

<Switch.Root id="disabled-switch" disabled defaultChecked={true}>

313

<Switch.Thumb />

314

</Switch.Root>

315

</div>

316

);

317

}

318

```

319

320

### With Custom Styling

321

322

```typescript

323

import * as Switch from "@radix-ui/react-switch";

324

import "./switch.css"; // Your custom styles

325

326

function StyledSwitch() {

327

return (

328

<Switch.Root className="switch-root">

329

<Switch.Thumb className="switch-thumb" />

330

</Switch.Root>

331

);

332

}

333

```

334

335

Example CSS:

336

337

```css

338

.switch-root {

339

width: 42px;

340

height: 25px;

341

background-color: gray;

342

border-radius: 9999px;

343

position: relative;

344

border: none;

345

cursor: pointer;

346

}

347

348

.switch-root[data-state="checked"] {

349

background-color: blue;

350

}

351

352

.switch-root[data-disabled] {

353

opacity: 0.5;

354

cursor: not-allowed;

355

}

356

357

.switch-thumb {

358

display: block;

359

width: 21px;

360

height: 21px;

361

background-color: white;

362

border-radius: 9999px;

363

transition: transform 100ms;

364

transform: translateX(2px);

365

will-change: transform;

366

}

367

368

.switch-thumb[data-state="checked"] {

369

transform: translateX(19px);

370

}

371

372

.switch-thumb[data-disabled] {

373

opacity: 0.8;

374

}

375

```

376

377

## Accessibility Features

378

379

- **ARIA Compliant**: Uses proper `role="switch"`, `aria-checked`, and `aria-required` attributes

380

- **Keyboard Navigation**: Space and Enter keys toggle the switch state

381

- **Screen Reader Support**: State changes are announced to assistive technologies

382

- **Focus Management**: Proper focus indicators and keyboard navigation

383

- **Form Integration**: Works seamlessly with native HTML form validation and submission

384

- **Disabled State**: Properly handles disabled state with appropriate ARIA attributes and visual indicators