How To Make Switch Component with React
Published: 2023-01-08 05:00:53

[✨ **Watch on YouTube**](https://youtu.be/QydSYsxXRvw)  |  [🐙 GitHub](https://github.com/RodionChachura/react-toolkit)  |  [🎮 Demo](https://reactkit.radzion.com/switch)

Let's make a nice switch or toggle component with React.

![](switch.png)

In props, we have value and onChange handler together with an optional label that we'll show next to the switch.

```tsx
import styled, { useTheme } from "styled-components"
import { defaultTransitionCSS } from "../animations/transitions"
import { CheckIcon } from "../icons/CheckIcon"
import { CloseIcon } from "../icons/CloseIcon"
import { HStack } from "../Stack"
import { Text } from "../Text"
import { centerContentCSS } from "../utils/centerContentCSS"
import { getCSSUnit } from "../utils/getCSSUnit"
import { getSameDimensionsCSS } from "../utils/getSameDimensionsCSS"
import { roundedCSS } from "../utils/roundedCSS"

interface SwitchProps {
  value: boolean
  onChange: (value: boolean) => void
  label?: string
}

const height = 28
const width = height * 1.58
const spacing = 2
const controlSize = height - spacing * 2

const Control = styled.div`
  ${getSameDimensionsCSS(controlSize)};

  ${roundedCSS};
  ${defaultTransitionCSS};

  ${centerContentCSS};
  color: ${({ theme }) => theme.colors.background.toCssValue()};
  font-size: 14px;
`

const Wrapper = styled(HStack)`
  cursor: pointer;

  color: ${({ theme }) => theme.colors.textSupporting.toCssValue()};

  :hover {
    color: ${({ theme }) => theme.colors.text.toCssValue()};
  }

  :hover ${Control} {
    transform: scale(1.08);
  }
`

const Container = styled.div`
  width: ${getCSSUnit(width)};
  height: ${getCSSUnit(height)};

  display: flex;
  align-items: center;

  ${roundedCSS};
  ${defaultTransitionCSS};
`

export const Switch = ({ value, onChange, label }: SwitchProps) => {
  const { colors } = useTheme()
  return (
    <Wrapper
      onClick={() => onChange(!value)}
      as="label"
      alignItems="center"
      gap={8}
      id={label}
    >
      <Container
        style={{
          background: (value
            ? colors.textSupporting3
            : colors.backgroundGlass2
          ).toCssValue(),
        }}
      >
        <Control
          style={{
            marginLeft: value ? width - controlSize - spacing : spacing,
            background: colors.text.toCssValue(),
          }}
        >
          {value ? <CheckIcon /> : <CloseIcon />}
        </Control>
      </Container>
      {label && <Text>{label}</Text>}
    </Wrapper>
  )
}
```

First, we render the `Wraper` that has the onClick handler so the user can also click on the text to toggle the value. On hover, we'll change the color and make the circle larger with the transform scale.

Then we display the container with fixed width and height. Its background will also change based on value, so the unchecked variant will have an almost transparent background.

`Control` has the size of container `height` minus two spacings. To make it move with animation, we set a transition and change the marginLeft property based on value.

I've designed the component for my productivity app Increaser. It utilizes a lot of colors already because every project has different colors. That's why it based on grayish colors and has an icon inside the circle to make it more intuitive for the user.