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 keyframes to your globals.css for the flip variant:
@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 {
Swap,
SwapIndicator
} from "@/registry/react/components/swap";<Swap>
<SwapIndicator type="on">
<MoonIcon />
</SwapIndicator>
<SwapIndicator type="off">
<SunIcon />
</SwapIndicator>
</Swap>Examples
Fade
Flip
Rotate
Scale
Blur
API Reference
Swap
| Prop | Type | Default |
|---|---|---|
variant | "fade" | "scale" | "flip" | "rotate" | "blur" | "fade" |
swap | boolean | - |
lazyMount | boolean | true |
unmountOnExit | boolean | true |
className | string | - |
asChild | boolean | - |
SwapIndicator
| Prop | Type | Default |
|---|---|---|
type | 'on' | 'off' | required |
className | string | - |
asChild | boolean | - |
For a complete list of props, see the Ark UI documentation.