How to Create a Switch from Scratch using GSAP in React

Germa Vinsmoke
JavaScript in Plain English
6 min readApr 16, 2022

--

Have you ever thought of creating a toggle switch on your own? That cool animation of moving the thumb from left to right or vice-versa? Or, are you the one who simply uses a library to add the switch quickly and get done with it? 😏

The simple-looking switches! Although they are great, we can do a lot better than this.

We can make something like this on our own from scratch 🤩😎.

So, let’s start making this. What about the prerequisites? I’ll be using GSAP and React to create this. React is completely optional, it can be made easily in vanilla JavaScript too. 🙃

You can also watch this video and follow the code. 😎

Project setup

I’ll be using Vite for creating the project because it’s a lot faster than its counterpart. The cold start and hot restart are also fast.

You can create the app using this command.

yarn create vite

Then, it’ll ask for the project name and the type of template which you would like to use. Currently, it supports these templates —

  • vanilla / vanilla-ts
  • vue / vue-ts
  • react / react-ts
  • preact / preact-ts
  • lit / lit-ts
  • svelte / svelte-ts

Again, you can select any one of these. I’ll go with React.

After the project is created, follow these commands:

cd <project-name>
yarn # To install the deps or npm install
yarn run dev # To run the dev server

The project will be running on port 3000. localhost:3000

The project setup part is done, so we can move to the basic UI part.

UI Part

We’ll be adding the JSX and CSS for the UI.

Switch-UI-JSX

Quite simple, a div for the background. One div is for the switch container and the last one is for the switch-thumb circle.

A span for the label, having the value of OFF. We’ll change it to FF and N later on. 🙃

We’ve used CIRCLE_WIDTH and SWITCH_WIDTH in variables because we will be using those at the time of animation.

Next is the CSS of the application.

Switch-UI-CSS

The output will look like this —

The next step is to add the state, refs and the toggle function.

Switch-state-refs-function

We created refs for switch-container, switch thumb and the label because we’ll be selecting the DOM elements of all these 3 things. After creating the refs, we attached the ref to the respective tags.

For toggle, we created a state with the name of switchState and gave it a default value of “off”. With the help of this state value, we can change the text inside our label.

At last, in order to change the switchState’s value, we created a function with the name of handleClick and attached it to the div with the class name of “switch-container”. It’s just checking the current value of switchState and updating it to the opposite of the current one.

The next and final step is to add the animation to our static switch 🤩

Animation Part

We’ll add the animation and also remove some of the CSS because it’ll be handled by the animation.

But first, if you haven’t installed GSAP, then you should:

yarn add gsap

This will add GSAP to our project and now we can import it inside our file. We’ll be using the GSAP timeline. You can learn more about it here.

Switch-animation

First, we imported GSAP and Elastic from the gsap module. Elastic is used for providing the value to ease (cubic-bezier curve value).

Then, we created the timeline variable.

const t1 = gsap.timeline()

With this variable, we can add the chain of animations.

Next, we brought in the useEffect hook because we want to call our animation whenever the switchState is going to change.

We’re running different animations based on the current state of the switchState.

Let’s pick one animation point at a time to understand what’s going on.

t1.to(
circleRef.current,
{
duration: 0.5,
x: SWITCH_WIDTH - CIRCLE_WIDTH,
backgroundColor: '#51ff0d',
ease: Elastic.easeOut.config(1, 0.6),
},
'start'
)

.to() means we want to change the current value to these values. 🙃

There are 3 parameters which we are using in this .to().

  • The first one is the target on which we want to add the animation. We gave it the DOM element of switch thumb.
  • The second is the option object in which we provide all kinds of CSS transformations or GSAP options (duration, ease, etc).
  • The third one is the label, it can be something else also, for example, ‘<’, ‘>’, ‘-=0.1’. If we give it a string like ‘start’ and provide the same value to some other .to() then both of them will start at the same point in time.

Let’s see more about the animation options object:

  • duration — 0.5, the value in seconds, that means the animation will take 0.5 seconds to complete.
  • x — same as translating on X axis, we’re using the value of SWITCH_WIDTH — CIRCLE_WIDTH.
  • backgroundColor — to change the color of the switch thumb
  • ease — the animation bezier curve value

The width in yellow is SWITCH_WIDTH, the red one is CIRCLE_WIDTH. We want to move the circle to the right side, so we subtract the values in order to get the distance. This distance can be used to tell the GSAP that we will move this thumb by this much.

Let’s see the next block of animation.

.to(
switchRef.current,
{
duration: 0.5,
borderColor: '#51ff0d',
},
'start'
)

Here, we’re targeting the DOM element of switch-container. We’re simply changing the color of the border. The label is the same as the previous block because we want to start both of these animations at the same time.

Onto the next and final block of ON state.

.fromTo(
labelRef.current,
{ y: 20, opacity: 0, color: 'white' },
{ y: 0, opacity: 1, color: '#51ff0d', duration: 0.5 },
'start'
);

This block is having a different timeline function. .fromTo() function means we want to change the values from “this” to “this”.

So, in this, we are targeting the DOM element of label. We’re moving the label from “y” of 20 to “y” of 0, the opacity from 0 to 1 and some color change also.

The duration parameter will be present in the second object to tell that this animation will take 0.5 seconds.

Again, we are using the same label because we want it to start along with the other two animations.

The else part animation is completely same, all we are doing is reversing the order of animation.

For example, instead of moving the switch thumb from:

0 — >(SWITCH_WIDTH — CIRCLE_WIDTH)

We’re moving it from:

(SWITCH_WIDTH — CIRCLE_WIDTH) — > 0

And after doing all this, you’ll be able to witness this cool-looking switch. 😎

That’s it, this is where our journey ends. I hope you were able to reach this point. 😃

Thanks! And stay tuned for more articles on animations. 🤩😎

And, lastly, the Github repo for this animation.

You can follow me on Twitter for some more content or can subscribe to my mailing list on Medium. 😁

More content at PlainEnglish.io. Sign up for our free weekly newsletter. Follow us on Twitter and LinkedIn. Join our community Discord.

--

--