How to build a React switch

Mathew Pregasen
Mathew Pregasen
Guest Writer

Nov 13, 2023

Sometimes, you just need to switch things up.

Say, from “on” to “off.” “Light mode” to “dark mode.” “Available” to “unavailable.”

The ever-toggleable React switch component is just the ticket to make that possible. And with React’s component-based architecture, it’s common for developers to build a React switch component that they can import across an application.

Let’s explore how to build a React switch from scratch, the basic component structure, and how to customize a switch component with consideration toward ease of use.

First things first, what is a React switch component?

A switch is a common UI component that displays and toggles a state between two possible values. It typically represents a boolean, like “True or False” and “Yes or No”. Additionally, under WAI-ARIA guidelines, there’s a third mixed state reflecting a partially checked checkbox. (Today’s example won’t cover that, but we encourage you to center accessibility and get familiar with those guidelines!)

Also, to be super clear, the switch component we’re working with today is not a JavaScript switch statement—which is a totally different native logic statement.

Why should you use a React switch component?

Building a React switch component makes it easy for a user to handle booleans. With a simple import statement, developers could drop-in a component that has all the bells and whistles to handle toggle events.

Designing the component

There are certain design considerations to keep in mind when building a robust React switch component. Ideally, the component needs to match your app or company’s design language without overcomplicating the switch’s logic or functionality.

Defining the basic component structure

The most simple React switch component needs two core input props:

  • A value variable that defines the switch’s state. This variable could be a number (e.g., 0 and 1) or string (e.g., “on” and “off”). However, it’s cleanest to use the native boolean type (e.g., true and false).
  • A onChange function that can be invoked to mutate the switch’s value. It’s important that this be a prop given React’s unidirectional data flow—the value shouldn’t ever be modified directly.

Additionally, a React switch requires a very basic HTML structure. Foremost, it needs a main container div whose background represents the switch’s state. It also needs a togglable switch element—a “handle” or “knob”—that moves upon click.

Technically, this can be accomplished with just a single div element in addition to its ::before or ::after properties being repurposed for the handle, but given that React is an abstraction layer that simplifies re-using code, such over-the-top conciseness isn’t generally necessary.

Supporting a color theme

In this example, we’ll use four color states—the color of the switch’s background and the switch’s handle as well as the same when the switch is enabled.

Some switches might bake these colors into the component if the switch is to appear the same throughout the application. But accepting additional props to alter these colors can be a nice optional feature, especially if the switch is used in alternative contexts (e.g., a negative context when the switch is disabling a feature).

Setting valid colors for the toggle switches

It’s important that the toggle switch communicates to the user when it is on versus off. In some cases, we might want to make these colors props so that the component can switch colors in various settings. (For instance, a switch disabling something might be red when on.)

Thankfully, React makes such customization easy. We just have to include two additional props—an `checkedColor` prop and an `uncheckedColor` prop where the valid colors are ingested into the component. Another set of two props—checkedHandleColor and uncheckedHandleColor—are fantastic for altering the handle or knob’s color theme.

Considering user interactions with the React switch

There are various user interactions to consider when building a React switch component. These include handling toggle events. Three common props are onToggle, onTrue, and onFalse to fire during the respective events.

These props enable the React switch to trigger logic whenever a user interacts with it.

Including a hidden native checkbox input

Finally, it’s important that the React switch contains a native input checkbox element that’s hidden with the correct data binding to the component’s props. This helps keep the underlying form accessible by using native form fields that are cleanly defined to the DOM. It’s quite easy to do this with a checkbox’s native props.

Coding the component

We’ll progressively build out the component, slowly adding more robust functionality to address the previous concerns.

Starting with a base component

Given a React switch component’s functionality is rather simple, we’ll start out with a simple functional component. To begin, we’ll populate it with a container div and an empty div that’ll become our handle.

1import React from "react";
2const Switch = ({
3 value,
4 onClick,
5}) => {
6 return (
7   <div>
8     <div></div>
9   </div>
10 );
11};
12export default Switch;
13

Adding functionality to change state

We’ll add an onClick function to the container div that’ll change the switch’s state on user interaction.

1import React from "react";
2const Switch = ({
3 value,
4 onClick,
5}) => {
6 return (
7   <div
8     onClick={() => {
9       onClick(!value);
10     }}
11   >
12     <div></div>
13   </div>
14 );
15};
16export default Switch;
17

Additional conditional styling to reflect state

We’ll now add some conditional CSS styling to reflect state. This could be done using defined CSS classes, but to stick with just JavaScript, we’ll use the native style prop. Here’s where you can really get creative with your switch’s look and feel. For my design, I’ll be utilizing the following techniques:

  • An absolutely positioned knob that’s always 3px from the border on either state. Here, using an absolutely positioned div is clean because the switch is a fixed size.
  • Conditionally set backgroundColor

My design might have code that looks like this:

1import React from "react";
2const SWITCH_WIDTH_PX = 72;
3const HANDLE_DIAMETER_PX = 30;
4const SWITCH_OFFSET_PX = 3;
5const Switch = ({
6 value,
7 onClick,
8}) => {
9 return (
10   <div
11     style={{
12       width: SWITCH_WIDTH_PX,
13       height: HANDLE_DIAMETER_PX + 2 * SWITCH_OFFSET_PX,
14       borderRadius: HANDLE_DIAMETER_PX,
15       border: "1px #ddd solid",
16       position: "relative",
17       cursor: "pointer",
18       background: value ? "blue" : "aliceblue",
19     }}
20     onClick={() => {
21       onClick(!value);
22     }}
23   >
24     <div
25       style={{
26         background: value ? “white” : “blue”,
27         borderRadius: "100%",
28         height: HANDLE_DIAMETER_PX,
29         width: HANDLE_DIAMETER_PX,
30         position: "absolute",
31         top: SWITCH_OFFSET_PX,
32         left: value
33           ? SWITCH_WIDTH_PX - HANDLE_DIAMETER_PX - SWITCH_OFFSET_PX
34           : SWITCH_OFFSET_PX,
35       }}
36     ></div>
37   </div>
38 );
39};
40export default Switch;
41

There are near-infinite ways to style your switch, so do whatever best fits your application! (And if you use any React CSS libraries like styled-components, be sure to leverage those for consistency across your application.)

Adding animation to your switch

We can use the native CSS transition property to add animation to our switch. We simply add a transition property to each element in our component—both the container and the handle:

1import React from "react";
2const SWITCH_WIDTH_PX = 72;
3const HANDLE_DIAMETER_PX = 30;
4const SWITCH_OFFSET_PX = 3;
5const Switch = ({
6 value,
7 onClick,
8}) => {
9 return (
10   <div
11     style={{
12       width: SWITCH_WIDTH_PX,
13       height: HANDLE_DIAMETER_PX + 2 * SWITCH_OFFSET_PX,
14       borderRadius: HANDLE_DIAMETER_PX,
15       border: "1px #ddd solid",
16       position: "relative",
17       transition: "1s",
18       cursor: "pointer",
19       background: value ? "blue" : "aliceblue",
20     }}
21     onClick={() => {
22       onClick(!value);
23     }}
24   >
25     <div
26       style={{
27         background: value ? “white” : “blue”,
28         borderRadius: "100%",
29         height: HANDLE_DIAMETER_PX,
30         width: HANDLE_DIAMETER_PX,
31         position: "absolute",
32         top: SWITCH_OFFSET_PX,
33         left: value
34           ? SWITCH_WIDTH_PX - HANDLE_DIAMETER_PX - SWITCH_OFFSET_PX
35           : SWITCH_OFFSET_PX,
36         transition: "1s",
37       }}
38     ></div>
39   </div>
40 );
41};
42export default Switch;
43

This gives the switch a natural one-second transition. Additionally, to meet a more thorough accessibility standard, you can disable transitions if a browser or OS-based “reduce motion” setting is ticked. (Separately, if you’re interested in learning more about animation in React, I cover that in this blog post on React animation libraries.)

Adding a hidden input box

Next, let’s add a hidden input box that’ll act as a DOM-recognized form element that also reflects a switch’s state. This helps with the switch’s accessibility.

1import React from "react";
2const SWITCH_WIDTH_PX = 72;
3const HANDLE_DIAMETER_PX = 30;
4const SWITCH_OFFSET_PX = 3;
5const Switch = ({
6 value,
7 onClick,
8}) => {
9 return (
10   <div
11     style={{
12       width: SWITCH_WIDTH_PX,
13       height: HANDLE_DIAMETER_PX + 2 * SWITCH_OFFSET_PX,
14       borderRadius: HANDLE_DIAMETER_PX,
15       border: "1px #ddd solid",
16       position: "relative",
17       transition: "1s",
18       cursor: "pointer",
19       background: value ? "blue" : "aliceblue",
20     }}
21     onClick={() => {
22       onClick(!value);
23     }}
24   >
25     <div
26       style={{
27         background: value ? “white” : “blue”,
28         borderRadius: "100%",
29         height: HANDLE_DIAMETER_PX,
30         width: HANDLE_DIAMETER_PX,
31         position: "absolute",
32         top: SWITCH_OFFSET_PX,
33         left: value
34           ? SWITCH_WIDTH_PX - HANDLE_DIAMETER_PX - SWITCH_OFFSET_PX
35           : SWITCH_OFFSET_PX,
36         transition: "1s",
37       }}
38     ></div>
39     <input
40       type="checkbox"
41       value={value}
42       onChange={(e) => {
43         onClick(e.target.value);
44       }}
45       style={{ display: "none" }}
46     />
47   </div>
48 );
49};
50export default Switch;
51

Using the native onChange function, we can easily toggle the switch’s value should the input box be altered with something like a screen reader.

Finally, add additional props for custom colors

If you want to alter the switch’s colors, we could also add some conditional declare statements to define these. We’ll scope these out into intra-class variables to avoid cluttering our style inputs that can also be set as props. Altogether, the component is defined as:

1import React from "react";
2const SWITCH_WIDTH_PX = 72;
3const HANDLE_DIAMETER_PX = 30;
4const SWITCH_OFFSET_PX = 3;
5const Switch = ({
6 containerCheckedColor = "blue",
7 containerUncheckedColor = "aliceblue",
8 handleCheckedColor = "white",
9 handleUncheckedColor = "blue",
10 value,
11 onClick,
12}) => {
13 return (
14   <div
15     style={{
16       width: SWITCH_WIDTH_PX,
17       height: HANDLE_DIAMETER_PX + 2 * SWITCH_OFFSET_PX,
18       borderRadius: HANDLE_DIAMETER_PX,
19       border: "1px #ddd solid",
20       position: "relative",
21       transition: "1s",
22       cursor: "pointer",
23       background: value ? containerCheckedColor : containerUncheckedColor,
24     }}
25     onClick={() => {
26       onClick(!value);
27     }}
28   >
29     <div
30       style={{
31         background: value ? handleCheckedColor : handleUncheckedColor,
32         borderRadius: "100%",
33         height: HANDLE_DIAMETER_PX,
34         width: HANDLE_DIAMETER_PX,
35         position: "absolute",
36         top: SWITCH_OFFSET_PX,
37         left: value
38           ? SWITCH_WIDTH_PX - HANDLE_DIAMETER_PX - SWITCH_OFFSET_PX
39           : SWITCH_OFFSET_PX,
40         transition: "1s",
41       }}
42     ></div>
43     <input
44       type="checkbox"
45       value={value}
46       onChange={(e) => {
47         onClick(e.target.value);
48       }}
49       style={{ display: "none" }}
50     />
51   </div>
52 );
53};
54export default Switch;
55

And just like that, we have a fully functional and customizable React switch component!

Closing thoughts

In this tutorial, we demonstrated how we could create a simple but personalizable React switch component to enable users to toggle boolean functions. The component built here ships with default colors, but those can be customized however you like. Additionally, the React switch is great for accessibility with its embedded native DOM element within the JSX.

Want to skip the lift? The best React component library is in Retool. We’ve got a React switch component ready to go—give it a try.

Reader

Mathew Pregasen
Mathew Pregasen
Guest Writer
Nov 13, 2023
Copied