Breaking down the task of producing a checkbox which is using SVG + GSAP
Tags: codepen, gsap, svg
Published: 2022-10-01 09:11:20

---
title: Breaking down the task of producing a checkbox which is using SVG + GSAP
published: true
tags: codepen, GSAP, SVG
---

## The SVG from Figma
Working on a project where a custom checkbox was designed, the design contained in Figma two states of the checkbox: checked and unchecked.

The two states were exported as SVG into two files. They looked quite similar, only some parts of it were located in different position, changed colour.

{% codepen https://codepen.io/netsi1964/pen/vYjjNBK  %}

That is fine - we have the states of the custom checkbox!

## The HTML and CSS to show a custom checkbox

When you want to produce a custom checkbox you should include a native HTML `input[type="checkbox"]`(this is the CSS selector for such an element). It will hold the state of the checkbox, and when used inside a HTML `form` if given a `[name]` attribute it will be send together with the rest of the form data.

You also get the benefit of keeping all native features from the solid HTML framework. No need to reinvent the wheel! :-) Like if you you change the `checked` state of the `input` element you can use `css` selectors to make the DOM react to it, without you having to do a lot of coding!

For instance here are some powerful CSS allows for state texts follow the state of the input element.

```
[type="checkbox"]:not(:checked) ~ .false,
[type="checkbox"]:checked ~ .true {
	display: none;
}
[type="checkbox"]:not(:checked) ~ .true,
[type="checkbox"]:checked ~ .false {
	display: block;
}
``` 

To break them down into words: 

> match elements of type checkbox, which has a given `:checked` state (say: `:not(:checked)`) then match a true or false class using [general sibling combinator "~"](https://developer.mozilla.org/en-US/docs/Web/CSS/General_sibling_combinator)

It can be a bit hard to understand at first, but is very powerful an all using vanilla CSS. These powerful CSS rules adds the option to have a sibling element containing say a text which can show on the `checked (true)` and `unchecked (false)` state! Here I use it to show `true|false` besides the beautiful custom checkbox.

The complete CSS based solution now looks like this: 

{% codepen https://codepen.io/netsi1964/pen/oNdomWz %}

## Adding animation with GSAP
I was asked if I could perhaps animate the checkbox. After doing some thinking I came to a conclusion that it would be only a matter of animating some `attributes` on parts of the SVG, since the two SVG states did not add or remove elements, but only had some small changes to elements which are in the designs.

GSAP is pretty good for animating attributes on a timeline using its [.to(..)](https://greensock.com/docs/v3/GSAP/gsap.to) method. It simply takes a `css selector` or a `DOM element` and some parameters which specifies the `attribute` to animate to which new `value`. Other than that it can be useful here to set a `duration` for the animation, and as all changes should be run simultaneously, a `label` for all the changes to align their starting point to.

The differences to animate I simply found by comparing the two SVG sources. In my code I then create a simple model to contain the changes I wanted to apply on a state change. Ended up with this list of animation request:

```
let animations = [
	{ selector: ".circle", checkedParams: { x: -20} },
	{ selector: ".bg", checkedParams: { fill: "#DCDDE6" } },
	{ selector: ".disk", checkedParams: { fill: "white" } },
	{ selector: ".checkmark", checkedParams: { stroke: "white" } }
];
```

An array which I can loop through when doing the animated state transition using GASP can be understand like this:

`selector`: Which CSS selector will match the element I want to animate changes to? For this to be realistic I have manually added a class (say `circle`) as a "handle" to match in a CSS selector.

`checkedParams`: An object containing key-values for attributes to animate. Like animate `x` to `-20`.

### Being the lazy programmer I am...
With many years of development on my back I have the joy of being also a bit lazy :-) My brain tries to optimize the manual work to do by automating what can be automated. In this case it showed up when I had to figure out how have values from both states in my `animations` object. I have specified `checkedParams`, but I also need to know the `uncheckedParams` which should contain hold values for the `unchecked (false)` state. 

At the time of coding I came up with an initialization function which will expand the `animations` object with the value for the attribute which will be animated. It looks like this:

``` 
function updateAnimation(animations) {
	return animations.map((a) => {
		let uncheckedParams = a.uncheckedParams;
		let { selector, checkedParams } = a;
		let keys = Object.keys(checkedParams);
		let ele = document.querySelector(selector);
		uncheckedParams = {};
		keys.forEach((key) => {
			const val = ele.getAttributeNode(key)?.nodeValue;
			uncheckedParams[key] = val !== undefined ? val : params[key];
		});
		return { ...a, uncheckedParams };
	});
}
``` 

See if you can figure my code out! :-)

> In hindsight I would probably simply enter them manually :-) But breaking the idea into `updateAnimation` function was a fun task!

## Finishing up the task
Only some small pieces of coding was added from here. Like adding a test where clicking somewhere else on the page would work (it did). Also the code to ensure that both a `checked` and `unchecked` initial state would work (also did, after some tries!).

## Going further with the project
I will be porting this into an Angular component, which is what we use in the project. However it would be nice to do more work on it producing say:

* A svelte implementation
* A NPM package
* A custom Element (web component)
* An online tool allowing to toggle between your own SVG designs and getting the code generated for you

Such small projects are good "coding fitness", and sharing them online - on CodePen, Github, NPM and other places is what makes our line of business so cool! Open Source rules! And do remember:

> If you take from the web, you should give to the web!

Happy coding!

/Sten Hougaard
[netsi1964 at CodePen](https://codepen.io/netsi1964) - [netsi1964 at Twitter](https://twitter.com/netsi1964)

## The final version - enjoy! 

{% codepen https://codepen.io/netsi1964/pen/yLjKraY %}