Icon Swap | Community Components | 21st

Icon Swap

Animate swapping between icons with scale, blur, and fade transitions when the active icon changes.

Usage

"use client"

import { IconSwap, IconSwapItem } from "@/components/ui/icon-swap"

import { useState } from "react"
import { MonitorIcon, MoonIcon, SunIcon } from "lucide-react"

import { Button } from "@/components/ui/icon-swap-utils/button"

const ICONS = {
  sun: SunIcon,
  moon: MoonIcon,
  monitor: MonitorIcon,
} as const

type IconKey = keyof typeof ICONS

export default function IconSwapDemo() {
  const [icon, setIcon] = useState<IconKey>("sun")

const Icon = ICONS[icon]

return (
    <div className="flex flex-col items-center gap-4">
      <Button
        className="relative will-change-transform"
        variant="outline"
        size="icon-sm"
        aria-label={icon}
      >
        <IconSwap>
          <IconSwapItem key={icon}>
            <Icon />
          </IconSwapItem>
        </IconSwap>
      </Button>

<div className="flex gap-0.5 rounded-lg p-0.5 ring-1 ring-line">
        {Object.keys(ICONS).map((key) => (
          <Button
            key={key}
            className="rounded-md border-none capitalize"
            size="xs"
            variant={icon === key ? "secondary" : "ghost"}
            onClick={() => setIcon(key as IconKey)}
          >
            {key}
          </Button>
        ))}
      </div>
    </div>
  )
}

Dependencies

motion lucide-react

Tags

Icon Animation Transition Swap Motion

Source

chanhdai.com

Published

7/22/2026