Toggle Icon with Tailwind CSS
A simple toggle
While I'm familiar with basic styling fundamentals to render information in a vanilla manner, I am by no means a UX designer. A growth area for me is developing an eye and implementing both elegant and functional designs. To this end I revamped my website's theme switcher from a simple button to a toggle. In this post I describe how I implemented the theme toggler I use on my website, and discuss the thought process I employ when trying to implement more complex components.
The thought process - display something to start
While you'll find code snippets below, the intention of this post is to discuss the thought process and creating the component,
please checkout the source code of my website.
Here you'll find the <ThemeSwitcher>
component and how I implemented it in a React component.
To begin, let's identify the main parts of the component and their properties. This I find is a helpful first step: breaking down a design into its building blocks, implementing, then building upon it.
- There is a sun or moon icon, exactly one of which is visible given the current theme.
- There is a circle that covers one of the icons which moves when the toggle is clicked.
- There are styling effects on the toggle, such as increasing in size on hover, color changing along with the theme, and an animation moving the circle.
To draw the icons we can create SVGs.
Even better we can reuse existing icons such as those from react-icons.
While we can also use an SVG for the circle I've opted for a <div>
tag which we'll apply styling to.
We'll also use Tailwind's height and width classes to provide some sizing to the elements.
return (
<div>
<LuMoon className='h-6 w-6'/>
<LuSun className='h-6 w-6'/>
<div className='border rounded-xl h-6 w-6'>
</div>
</div>
)
This results with the following:
Decide the layout
I envision the slider to be horizontal (although try it vertically for a challenge!) As such flexbox with the horizontal main axis is well-suited for laying out the components. We can apply the flex properties the parent div wrapper.
For the circle we want it to overlay either of the icons, depending on the current theme.
We can apply absolute
to the circle div to start, then apply a translation when the theme changes.
We apply a grey and yellow background color to fill the circle.
return (
<div className="flex justify-between align-middle">
<LuMoon className='h-6 w-6'/>
<LuSun className='h-6 w-6'/>
<div className='border rounded-xl h-6 w-6 absolute bg-gray-900 border-gray-900 dark:bg-yellow-500'>
</div>
</div>
);
Tying it together
Finally we link our toggle to our theme state provider.
For me I use the next-themes library for theme management.
The useTheme
function provides hooks getting and setting the theme, the latter which we use to update the theme via the onClick
prop of the wrapper div.
To the circle div, we add the following Tailwind classes to implement the sliding part of the toggle.
transition duration-200 ease-linear
enables a 200ms animation.
When the theme is dark the translate-x-6
class translates the circle along the x axis.
In combination with ease-linear
the reverse translation will occur when the theme is switched to light, completing the toggle animation.
import { useTheme } from 'next-themes';
export const SnippetThree = () => {
const { theme, setTheme } = useTheme();
const toggleAndSetTheme = () => setTheme(theme === "dark" ? "light" : "dark");
return (
<div
className="flex justify-between align-middle"
onClick={() => toggleAndSetTheme()}>
<LuMoon className='h-6 w-6'/>
<LuSun className='h-6 w-6'/>
<div className={`border rounded-xl h-6 w-6 absolute bg-gray-900 border-gray-900 dark:bg-yellow-500 transition duration-200 ease-linear ${theme === "dark" && "translate-x-6"}`}>
</div>
</div>
);
}
resulting in
Conclusion
In this post I covered how I implemented the toggle switch I use on my personal website. To expand on this, you may want to explore adding flair to the toggle such as rounded borders, sparkling effect, or resizing on hover.