text: Create a Toggle Switch in React as a Reusable Component
  Free JavaScript Book!
  Write powerful, clean and maintainable JavaScript.
  RRP $11.95
  In this article, we’re going to create an iOS-inspired toggle switch using React. This will be a small, self-contained component that you’ll be able to reuse in future projects. As we go, we’ll also build a simple demo React app that uses our custom toggle switch component.
  We could use third-party libraries for this, but building from scratch allows us to better understand how our code is working and allows us to customize our component completely.
  Forms provide a major means for enabling user interactions. The checkbox is traditionally used for collecting binary data — such as yes or no, true or false, enable or disable, on or off, etc. Although some modern interface designs steer away from form fields when creating toggle switches, I’ll stick with them here due to their greater accessibility.
  Here’s a screenshot of the component we’ll be building:
  Getting Started
  Let’s use Create React App to get a React app up and running quickly. If you’re unfamiliar with Create React App, check out our getting started guide.
  create-react-app toggleswitch
  Once everything has installed, change into the newly created directory and start the server with
  yarn start (or
  npm start if you prefer). This will start the development server at.
  Next, create a
  ToggleSwitch directory in the
  src directory. This is where we will make our component:
  mkdir src/ToggleSwitch
  In this directory, make two files:
  ToggleSwitch.js and
  ToggleSwitch.scss:
  touch ToggleSwitch.js ToggleSwitch.scss
  Finally, alter
  App.js as follows:
  import React from 'react'; import ToggleSwitch from './ToggleSwitch/ToggleSwitch' function App() { return ( <ToggleSwitch /> ); } export default App;
  The Markup
  We can start with a basic HTML checkbox input form element with its necessary properties set:
  <input type="checkbox" name="name" id="id" />
  To build around it, we might need an enclosing
  <div> with a
  class, a
  <label> and the
  <input /> control itself. Adding everything, we might get something like this:
  <div class="toggle-switch"> <input type="checkbox" class="toggle-switch-checkbox" name="toggleSwitch" id="toggleSwitch" /> <label class="toggle-switch-label" for="toggleSwitch"> Toggle Me! </label> </div>
  In time, we can get rid of the label text and use the
  <label> tag to check or uncheck the checkbox input control. Inside the
  <label>, let’s add two
  <span> tags that help us construct the switch holder and the toggling switch itself:
  <div class="toggle-switch"> <input type="checkbox" class="toggle-switch-checkbox" name="toggleSwitch" id="toggleSwitch" /> <label class="toggle-switch-label" for="toggleSwitch"> <span class="toggle-switch-inner"></span> <span class="toggle-switch-switch"></span> </label> </div>
  Converting to a React Component
  Now that we know what needs to go into the HTML, all we need to do is to convert the HTML into a React component. Let’s start with a basic component here. We’ll make this a class component, and then we’ll convert it into hooks, as it’s easier for new developers to follow
  state than
  useState.
  Add the following to
  src/ToggleSwitch/ToggleSwitch.js:
  import React, { Component } from "react"; class ToggleSwitch extends Component { render() { return ( <div className="toggle-switch"> <input type="checkbox" className="toggle-switch-checkbox" name="toggleSwitch" id="toggleSwitch" /> <label className="toggle-switch-label" htmlFor="toggleSwitch"> <span className="toggle-switch-inner" /> <span className="toggle-switch-switch" /> </label> </div> ); } } export default ToggleSwitch;
  At this point, it’s not possible to have multiple toggle switch sliders on the same view or same page due to the repetition of
  ids. We could leverage React’s way of componentization here, but in this instance, we’ll be using
  props to dynamically populate the values:
  import React, { Component } from 'react'; class ToggleSwitch extends Component { render() { return ( <div className="toggle-switch"> <input type="checkbox" className="toggle-switch-checkbox" name={this.props.Name} id={this.props.Name} /> <label className="toggle-switch-label" htmlFor={this.props.Name}> <span className="toggle-switch-inner" /> <span className="toggle-switch-switch" /> </label> </div> ); } } export default ToggleSwitch;
  The
  this.props.Name will populate the values of
  id,
  name and
  for (note that it is
  htmlFor in React JS) dynamically, so that you can pass different values to the component and have multiple instances on the same page. Also notice that the
  <span> tag doesn’t have an ending
  </span> tag. Instead, it’s closed in the starting tag like
  <span />, and in terms of JSX this is completely fine.
  Test this out by changing the contents of
  App.js as follows:
  function App() { return ( <> <ToggleSwitch Name='newsletter' /> <ToggleSwitch Name='daily' /> <ToggleSwitch Name='weekly' /> <ToggleSwitch Name='monthly' /> </> ); }
  Inspect the resultant output at (possibly using your browser’s dev tools) and ensure everything is working correctly.
  Styling and SCSS
  I recently wrote about styling React Components, where I compared the various ways this was possible. In that article, I concluded that SCSS is the best method, and that’s what we’ll use here.
  For SCSS to work with Create React App, you’ll need to install the node-sass package:
  yarn add node-sass
  We’ll also need to import the correct file into our component:
  // ToggleSwitch.js import React, { Component } from 'react'; import './ToggleSwitch.scss'; ...
  Now for the styling. This is a rough outline of what we’re after:
  - By default, the switch is going to be only
  75pxwide and vertically aligned
  inline-blockso that it’s inline with the text and doesn’t cause layout problems.
  - We’ll make sure that the control is not selectable so that users can’t drag and drop it.
  - We’ll be hiding the original checkbox input.
  - Both the
  ::afterand
  ::beforepseudo-elements needs to be styled and made into elements to get them into the DOM and style them.
  - We’ll also add some CSS transitions for a cool animated effect.
  And this is what that looks like in SCSS. Add the following to
  src/ToggleSwitch/ToggleSwitch.scss:
  .toggle-switch { position: relative; width: 75px; display: inline-block; vertical-align: middle; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; text-align: left; &-checkbox { display: none; } &-label { display: block; overflow: hidden; cursor: pointer; border: 0 solid #bbb; border-radius: 20px; margin: 0; } &-inner { display: block; width: 200%; margin-left: -100%; transition: margin 0.3s ease-in 0s; &:before, &:after { display: block; float: left; width: 50%; height: 34px; padding: 0; line-height: 34px; font-size: 14px; color: white; font-weight: bold; box-sizing: border-box; } &:before { content: "Yes"; text-transform: uppercase; padding-left: 10px; background-color: #f90; color: #fff; } } &-disabled { background-color: #ddd; cursor: not-allowed; &:before { background-color: #ddd; cursor: not-allowed; } } &-inner:after { content: "No"; text-transform: uppercase; padding-right: 10px; background-color: #bbb; color: #fff; text-align: right; } &-switch { display: block; width: 24px; margin: 5px; background: #fff; position: absolute; top: 0; bottom: 0; right: 40px; border: 0 solid #bbb; border-radius: 20px; transition: all 0.3s ease-in 0s; } &-checkbox:checked + &-label { .toggle-switch-inner { margin-left: 0; } .toggle-switch-switch { right: 0px; } } }
  Assuming you’re following along, if you head to the dev server at you’ll now see four nicely styled toggle switches. Try toggling them; they should all work.
  Also take a while to go through the code above. If there’s anything you’re unsure about, you can consult the Sass documentation, or head over to the SitePoint Forums and ask a question.
  Dynamic Labels
  Currently, the toggle options are hard coded:
  .toggle-switch { ... &-inner { ... &:before { content: "Yes"; ... } } ... &-inner:after { content: "No"; ... } ... }
  To make the component more flexible, we can grab these dynamically from the control using HTML5 data-attributes:
  &:before { content: attr(data-yes); ... } &-inner:after { content: attr(data-no); ... }
  We’ll hardcode the data attributes for testing, but will make this more flexible in the final version:
  // ToggleSwitch.js class ToggleSwitch extends Component { render() { return ( <div className="toggle-switch"> ... <label className="toggle-switch-label" htmlFor={this.props.Name}> <span className="toggle-switch-inner" data- <span className="toggle-switch-switch" /> </label> </div> ); } }
  A Smaller Component Version
  Also, for smaller screens, it would be a great idea to use a smaller version of switch, without the text. So let’s add the styling for it with some minimal sizes and removing the text:
  .toggle-switch { ... &.small-switch { width: 40px; .toggle-switch-inner { &:after, &:before { content: ""; height: 20px; line-height: 20px; } } .toggle-switch-switch { width: 16px; right: 20px; margin: 2px; } } }
  With respect to responsiveness, we should be changing the complete size, so let’s use the CSS scale function. Here we’ve covered all the Bootstrap-based responsive widths of devices:
  .toggle-switch { ... @media screen and (max-width: 991px) { transform: scale(0.9); } @media screen and (max-width: 767px) { transform: scale(0.825); } @media screen and (max-width: 575px) { transform: scale(0.75); } }
  You can test this out by adding the
  small-switch class to the parent
  <div> element in
  ToggleSwitch.js:
  class ToggleSwitch extends Component { render() { return ( <div className="toggle-switch small-switch"> ... </div> ); } }
  Head back to the dev server and test your changes. If you’d like to check what you have against the finished SCSS file, you can find that here.
  Theming in SCSS
  Since we can use variables in SCSS, adding support for multiple color themes in our app is made easier. You can read more about this in “Sass Theming: The Never Ending Story”. We’ll be using some color themes here and change all the raw colors to variables. The first three lines are a configurable set of colors, which helps us theme our little control:
  // Colors $label-colour: #bbb; $disabled-colour: #ddd; $toggle-colour: #2F855A; $white: #fff; // Styles .toggle-switch { ... &-label { ... border: 0 solid $label-colour; } &-inner { ... &:before { ... background-color: $toggle-colour; color: $white; } } &-disabled { background-color: $disabled-colour; cursor: not-allowed; &:before { background-color: $disabled-colour; cursor: not-allowed; } } &-inner:after { ... background-color: $label-colour; color: $white; } &-switch { ... background: $white; border: 0 solid $label-colour; } ... }
  And that’s it with the styling. Now let’s add some interactivity.
  Interactions and JavaScript
  Please note that the following section only contains demo code to explain the concepts. You should not be updating your actual
  ToggleSwitch component in this section.
  Our basic component will be a dumb component (also known as presentation component) whose state will be controlled by a parent component or container such as a
  form. What do we mean by controlled? Well, let’s look at an uncontrolled version first:
  import React from 'react'; const ToggleSwitch = () => ( <div> <input type="checkbox" className="toggle-switch-checkbox" /> </div> ); export default ToggleSwitch;
  When users interact with the above checkbox input, it will toggle between a checked and unchecked state of its own accord, without us having to write any JavaScript. HTML input elements are capable of managing their own internal state and they do this by updating the DOM directly.
  In React, however, it’s recommended we use controlled components, as the following example shows:
  import React from 'react'; const ToggleSwitch = ({checked}) => ( <div> <input type="checkbox" className="toggle-switch-checkbox" checked={checked} /> </div> ); export default ToggleSwitch;
  Here, React is controlling the state of the checkbox input. All interactions with this input have to go through the virtual DOM. If you try to interact with the component as it is, nothing will happen, as we haven’t defined any JavaScript code that can change the value of the
  checked prop we’re passing in.
  To fix this, we can pass in an
  onChange prop — a function to be called whenever the checkbox is clicked:
  import React from 'react'; const ToggleSwitch = ({checked, onChange}) => ( <div> <input type="checkbox" className="toggle-switch-checkbox" checked={checked} onChange={e => onChange(e.target.checked)} /> </div> ); export default ToggleSwitch;
  Now the checkbox input is interactive. Users can toggle the component “on” and “off” just like before. The only difference here is that state is controlled by React as opposed to the earlier uncontrolled version. By doing it this way, we can easily access the state of our component at any given time via JavaScript. We can also easily define the initial value when declaring the component.
  Now let’s have a look at how to use the
  ToggleSwitch component. Below is a simplified class-based example:
  import React, { Component } from 'react'; class Form extends Component { state = { checked : false } onChange = newValue => { this.setState({ checked: newValue }); } render() { return ( <ToggleSwitch id="toggleSwitch" checked={this.checked} onChange={this.onChange} /> ); } } export default Form;
  Now let’s convert the class-based component into a functional component using hooks:
  import React, { useState } from 'react'; export default function Form() { let [checked, setChecked] = useState(false); return ( <ToggleSwitch id="toggleSwitch" checked={checked} onChange={setChecked} /> ) }
  As you can see, we drastically cut down on the number of lines using functional component with the hooks creation method.
  If hooks in React are new for you, check out our guide, “React Hooks: How to Get Started & Build Your Own”.
  Finalizing the ToggleSwitch Component
  Now let’s get back to our
  ToggleSwitch component. We’ll need the following props:
  id(required): this is the
  idthat’s going to be passed to the checkbox input control. Without this, the component won’t render.
  checked(required): this will hold the current state, which will be a boolean value.
  onChange(required): this function will be called when the input’s
  onChangeevent handler is triggered.
  name(optional): this will be label text of the checkbox input, but we generally won’t be using this.
  small(optional): this is a boolean value, which renders the Toggle Switch in a small mode, where the text isn’t rendered.
  optionLabels(optional): if you aren’t using the
  smallversion of the control, you might need to pass this to the Toggle Switch as an array of two values, which signify the text for True and False. An example would be
  Text={["Yes", "No"]}.
  disabled(optional): this will be directly passed to the
  <input type="checkbox" />.
  When not using the
  small version, the following
  optionLabels text will be used as default:
  // Set optionLabels for rendering. ToggleSwitch.defaultProps = { optionLabels: ["Yes", "No"], };
  Since most of the props have to be set by the user and we can’t use arbitrary values, it’s always better to stop rendering if the required props aren’t passed in. This can be done using a simple JavaScript
  if statement or a ternary operator using
  ? : or a short-circuited
  &&:
  {this.props.id ? ( <!-- display the control --> ) : null}
  As our app grows, we can catch a lot of bugs with type checking. React has some built-in type-checking abilities. To run type checking on the props for a component, you can assign the special
  propTypes property. We can enforce the above list of props using React’s PropType library, which is a separate library that exports a range of validators that can be used to make sure the data you receive is valid.
  You can install it like so:
  yarn add prop-types
  Then, import the PropTypes library using:
  // ToggleSwitch.js import PropTypes from "prop-types";
  We’ll define the PropTypes in the following way: };
  By way of explanation:
  PropTypes.string.isRequired: this is a string value and it’s required and mandatory.
  PropTypes.string: this is a string value but it isn’t mandatory.
  PropTypes.func: this is a prop that takes in a function as value, but it isn’t mandatory.
  PropTypes.bool: this is a boolean value, but it isn’t mandatory.
  PropTypes.array: this is an array value, but it isn’t mandatory.
  Now we can carry on with the
  ToggleSwitch component. Replace the contents of
  src/ToggleSwitch/ToggleSwitch.js with the following:
  import React from "react"; import PropTypes from "prop-types"; import './ToggleSwitch.scss'; /* Toggle Switch Component Note: id, checked and onChange are required for ToggleSwitch component to function. The props name, small, disabled and optionLabels are optional. Usage: <ToggleSwitch id="id" checked={value} onChange={checked => setValue(checked)}} /> */ const ToggleSwitch = ({ id, name, checked, onChange, optionLabels, small, disabled }) => { return ( <div className={"toggle-switch" + (small ? " small-switch" : "")}> <input type="checkbox" name={name} className="toggle-switch-checkbox" id={id} checked={checked} onChange={e => onChange(e.target.checked)} disabled={disabled} /> {id ? ( <label className="toggle-switch-label" htmlFor={id}> <span className={ disabled ? "toggle-switch-inner toggle-switch-disabled" : "toggle-switch-inner" } data-yes={optionLabels[0]} data-no={optionLabels[1]} /> <span className={ disabled ? "toggle-switch-switch toggle-switch-disabled" : "toggle-switch-switch" } /> </label> ) : null} </div> ); } // Set optionLabels for rendering. ToggleSwitch.defaultProps = { optionLabels: ["Yes", "No"], }; }; export default ToggleSwitch;
  Finally, to test the component, change
  App.js like so:
  import React, { useState } from 'react'; import ToggleSwitch from './ToggleSwitch/ToggleSwitch' function App() { let [newsletter, setNewsletter] = useState(false); const onNewsletterChange = (checked) => { setNewsletter(checked); } return ( <> <ToggleSwitch id="newsletter" checked={ newsletter } onChange={ onNewsletterChange } /> <label htmlFor="newsletter">Subscribe to our Newsletter</label> </> ); } export default App;
  Now, when you head to you should see the working toggle.
  Making the Component Keyboard Accessible
  The final step is to make our component keyboard accessible. To do this, first alter the label like so:
  // ToggleSwitch.js <label className="toggle-switch-label" htmlFor={id} tabIndex={ disabled ? -1 : 1 } onKeyDown={ e => handleKeyPress(e) }> ... </label>
  As you can see, we’ve added a
  tabIndex property, which we’re setting to
  1 (focusable) or
  -1 (not focusable) depending on whether the component is currently disabled.
  We’ve also declared a
  handleKeyPress function to deal with it receiving keyboard input:
  function handleKeyPress(e){ if (e.keyCode !== 32) return; e.preventDefault(); onChange(!checked) }
  This checks if the key pressed is the space bar. If so, it prevents the browser’s default action (scroll the page in this case) and toggles the component’s state.
  And that’s essentially all you need. The component is now keyboard accessible.
  However, there’s a slight problem. If you click the
  ToggleSwitch component, you now get an outline around the entire component, and this is probably not desired. To combat this, we can alter things slightly to make sure it receives an outline when it’s focused with the keyboard, but not when it’s clicked:
  // ToggleSwitch.js <span className={ disabled ? "toggle-switch-inner toggle-switch-disabled" : "toggle-switch-inner" } data-yes={optionLabels[0]} data-no={optionLabels[1]} tabIndex={-1} /> <span className={ disabled ? "toggle-switch-switch toggle-switch-disabled" : "toggle-switch-switch" } tabIndex={-1} />
  Here we’ve added a
  tabIndex property to both of the inner
  <span> elements to ensure they can’t receive focus.
  Then, in
  ToggleSwitch.scss:
  $focus-color: #ff0; .toggle-switch { ... &-label { ... &:focus { outline: none; > span { box-shadow: 0 0 2px 5px $focus-color; } } > span:focus { outline: none; } } ... }
  This will apply a style to the
  ToggleSwitch’s inner
  <span> element when it’s focused with the keyboard, but not when it’s clicked. You can read more about this technique here. It’s slightly hacky, and should be dropped in favor of using :focus-visible, as soon as that gains wide enough browser support.
  A More Complete Example
  To finish off, I’d like to demonstrate a more complete example of using the
  ToggleSwitch component in the following CodeSandbox.
  This demo uses multiple
  ToggleSwitch components on the same page. The state of the last three toggles depends on the state of the first. That is, you need to accept marketing mails before you can refine your choice of which ones to receive.
  Summary
  In this article, I’ve shown how to create a reusable, iOS-inspired toggle switch using React. We looked at styling the component with SCSS, making it a controlled component, how to customize it by passing it props and how to make it keyboard accessible.
  You can find the complete code for the toggle switch on our GitHub repo.
  Get practical advice to start your career in programming!
  Master complex transitions, transformations and animations in CSS!