Toggle Button

A button that cycles through different options when clicked. Each click moves to the next option in the list.

Install dependencies

npm i framer-motion

Utility function

Create a file lib/utils.ts and paste this code

import { ClassValue, clsx } from 'clsx'; import { twMerge } from 'tailwind-merge'; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); }

Toggle Button

Create a file toggle-button.tsx in your components folder and paste this code

'use client'; import { cn } from '@/lib/utils'; import { AnimatePresence, motion } from 'framer-motion'; import React, { useState } from 'react'; type ToggleButtonProps = { options: Array<{ label: React.ReactNode; value: string; }>; defaultValue?: string; className?: string; onClick?: (value: string) => void; }; const ToggleButton = ({ options, defaultValue, onClick, className, ...props }: ToggleButtonProps) => { const [activeValue, setActiveValue] = useState(defaultValue || options[0].value); const handleClick = (value: string) => { const currentIndex = options.findIndex((option) => option.value === value); const nextIndex = (currentIndex + 1) % options.length; const newValue = options[nextIndex].value; setActiveValue(newValue); if (onClick) onClick(newValue); }; return ( <button onClick={() => handleClick(activeValue)} className={cn( 'relative border-2 border-zinc-700 hover:border-zinc-500 hover:bg-zinc-900 flex items-center justify-center h-[45px] w-[45px] rounded-full overflow-hidden', className )} {...props} > <div className="relative overflow-hidden h-full w-full flex items-center justify-center"> <AnimatePresence mode="popLayout"> {options.map((option) => { if (option.value !== activeValue) return null; return ( <motion.div key={option.value} className="absolute flex items-center justify-center" initial={{ y: 40 }} animate={{ y: 0 }} exit={{ y: -40 }} transition={{ type: 'spring', stiffness: 300, damping: 30 }} > {option.label} </motion.div> ); })} </AnimatePresence> </div> </button> ); }; export default ToggleButton;

Usage

<ToggleButton options={[ { label: <Sun size={18} />, value: 'Sun' }, { label: <Moon size={18} />, value: 'Moon' }, { label: <Rocket size={18} />, value: 'Rocket' } ]} defaultValue="Sun" />

Click the button to toggle