shadcn.io is not affiliated with official shadcn/ui
Shadcn Swap for React and Tailwind
Animate between two visual states with smooth transitions.
Installation
bunx --bun shadcn@latest add https://kit.dev/r/swap.jsonpnpm dlx shadcn@latest add https://kit.dev/r/swap.jsonnpx shadcn@latest add https://kit.dev/r/swap.jsonyarn shadcn@latest add https://kit.dev/r/swap.jsonInstall the following dependencies:
bun add @ark-ui/react tailwind-variantspnpm add @ark-ui/react tailwind-variantsnpm install @ark-ui/react tailwind-variantsyarn add @ark-ui/react tailwind-variantsAdd the following to your globals.css.
@theme inline {
--animate-flip-in: flip-in 0.2s ease-out;
--animate-flip-out: flip-out 0.2s ease-out;
}
@keyframes flip-in {
from { transform: rotateY(180deg); }
to { transform: rotateY(0deg); }
}
@keyframes flip-out {
from { transform: rotateY(0deg); }
to { transform: rotateY(180deg); }
}Copy and paste the following code into your project.
"use client";
import { Swap as ArkSwap, useSwapContext } from "@ark-ui/react/swap";
import type React from "react";
import { tv, type VariantProps } from "tailwind-variants";
import { cn } from "@/lib/utils";
export const useSwap = useSwapContext;
const swapIndicatorVariants = tv({
base: ["[&>span]:motion-reduce:animate-none!"],
variants: {
variant: {
fade: [
"[&>span]:data-[state=open]:fade-in-0 [&>span]:data-[state=open]:animate-in [&>span]:data-[state=open]:duration-200",
"[&>span]:data-[state=closed]:fade-out-0 [&>span]:data-[state=closed]:animate-out [&>span]:data-[state=closed]:duration-100",
],
scale: [
"[&>span]:data-[state=open]:zoom-in-0 [&>span]:data-[state=open]:fade-in-0 [&>span]:data-[state=open]:animate-in [&>span]:data-[state=open]:duration-200",
"[&>span]:data-[state=closed]:zoom-out-100 [&>span]:data-[state=closed]:fade-out-0 [&>span]:data-[state=closed]:animate-out [&>span]:data-[state=closed]:duration-100",
],
flip: [
"[&>span]:backface-hidden",
"[&>span]:data-[state=open]:animate-[flip-in_400ms_ease]",
"[&>span]:data-[state=closed]:animate-[flip-out_200ms_ease]",
],
rotate: [
"[&>span]:data-[state=open]:spin-in-[-90deg] [&>span]:data-[state=open]:fade-in-0 [&>span]:data-[state=open]:animate-in [&>span]:data-[state=open]:duration-250",
"[&>span]:data-[state=closed]:spin-out-[90deg] [&>span]:data-[state=closed]:fade-out-0 [&>span]:data-[state=closed]:animate-out [&>span]:data-[state=closed]:duration-100",
],
blur: [
"[&>span]:data-[state=open]:fade-in-0 [&>span]:data-[state=open]:zoom-in-50 [&>span]:data-[state=open]:animate-in [&>span]:data-[state=open]:blur-in-sm [&>span]:data-[state=open]:duration-250",
"[&>span]:data-[state=closed]:fade-out-0 [&>span]:data-[state=closed]:zoom-out-50 [&>span]:data-[state=closed]:animate-out [&>span]:data-[state=closed]:blur-out-sm [&>span]:data-[state=closed]:duration-150",
],
},
},
defaultVariants: {
variant: "fade",
},
});
interface SwapProps
extends React.ComponentProps<typeof ArkSwap.Root>,
VariantProps<typeof swapIndicatorVariants> {}
export const Swap = (props: SwapProps) => {
const {
variant = "fade",
lazyMount = true,
unmountOnExit = true,
className,
...rest
} = props;
return (
<ArkSwap.Root
className={cn(swapIndicatorVariants({ variant }), className)}
data-slot="swap"
lazyMount={lazyMount}
unmountOnExit={unmountOnExit}
{...rest}
/>
);
};
export const SwapIndicator = (
props: React.ComponentProps<typeof ArkSwap.Indicator>
) => <ArkSwap.Indicator data-slot="swap-indicator" {...props} />;Update the import paths to match your project setup.
Usage
import { MoonIcon, SunIcon } from "lucide-react";
import React from "react";
import { Button } from "@/components/ui/button";
import { Swap, SwapIndicator } from "@/components/ui/swap";const SwapDemo = () => {
const [swap, setSwap] = React.useState(false);
return (
<Button onClick={() => setSwap(!swap)} size="icon-lg" variant="outline">
<Swap swap={swap} variant="fade">
<SwapIndicator type="on">
<MoonIcon />
</SwapIndicator>
<SwapIndicator type="off">
<SunIcon />
</SwapIndicator>
</Swap>
</Button>
);
};Accessibility
| Key | Description |
|---|---|
Enter | Activate the focused control. |
Space | Activate the focused control. |
Demos
Blur
Flip
Rotate
Scale
API Reference
Swap
span
PropType
AttributeType
SwapIndicator
span
PropType
AttributeType
useSwap
PropType