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 http://localhost:3000.
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 id
s. 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 http://localhost:3000/ (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
75px
wide and vertically alignedinline-block
so 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
::after
and::before
pseudo-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 http://localhost:3000/ 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-yes="Ja" data-no="Nein"/>
<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.
Continue reading Create a Toggle Switch in React as a Reusable Component on SitePoint.
No comments:
Post a Comment