# Swap
URL: https://ark-ui.com/docs/utilities/swap
Source: https://raw.githubusercontent.com/chakra-ui/ark/refs/heads/main/website/src/content/pages/utilities/swap.mdx
Animate between two visual states with smooth transitions.
---
## Anatomy
```tsx
```
## Examples
### Fade
Swap between two icons with a fade animation. Set the `swap` prop to toggle between the `on` and `off` indicators.
**Example: fade**
#### React
```tsx
import { Swap } from '@ark-ui/react/swap'
import { CheckIcon, XIcon } from 'lucide-react'
import { useState } from 'react'
import styles from 'styles/swap.module.css'
export const Fade = () => {
const [swapped, setSwapped] = useState(false)
return (
)
}
```
#### Solid
```tsx
import { Swap } from '@ark-ui/solid/swap'
import { CheckIcon, XIcon } from 'lucide-solid'
import { createSignal } from 'solid-js'
import styles from 'styles/swap.module.css'
export const Fade = () => {
const [swapped, setSwapped] = createSignal(false)
return (
)
}
```
#### Vue
```vue
```
#### Svelte
```svelte
```
### Flip
Add a 3D flip effect by setting `perspective` on the root and using `rotateY` keyframes on the indicators.
**Example: flip**
#### React
```tsx
import { Swap } from '@ark-ui/react/swap'
import { PauseIcon, PlayIcon } from 'lucide-react'
import { useState } from 'react'
import styles from 'styles/swap.module.css'
export const Flip = () => {
const [swapped, setSwapped] = useState(false)
return (
)
}
```
#### Solid
```tsx
import { Swap } from '@ark-ui/solid/swap'
import { PauseIcon, PlayIcon } from 'lucide-solid'
import { createSignal } from 'solid-js'
import styles from 'styles/swap.module.css'
export const Flip = () => {
const [swapped, setSwapped] = createSignal(false)
return (
)
}
```
#### Vue
```vue
```
#### Svelte
```svelte
```
### Rotate
Rotate the indicators in and out with a spin transition.
**Example: rotate**
#### React
```tsx
import { Swap } from '@ark-ui/react/swap'
import { MoonIcon, SunIcon } from 'lucide-react'
import { useState } from 'react'
import styles from 'styles/swap.module.css'
export const Rotate = () => {
const [swapped, setSwapped] = useState(false)
return (
)
}
```
#### Solid
```tsx
import { Swap } from '@ark-ui/solid/swap'
import { MoonIcon, SunIcon } from 'lucide-solid'
import { createSignal } from 'solid-js'
import styles from 'styles/swap.module.css'
export const Rotate = () => {
const [swapped, setSwapped] = createSignal(false)
return (
)
}
```
#### Vue
```vue
```
#### Svelte
```svelte
```
### Scale
Scale the indicators up and down for a pop-in effect.
**Example: scale**
#### React
```tsx
import { Swap } from '@ark-ui/react/swap'
import { Volume2Icon, VolumeXIcon } from 'lucide-react'
import { useState } from 'react'
import styles from 'styles/swap.module.css'
export const Scale = () => {
const [swapped, setSwapped] = useState(false)
return (
)
}
```
#### Solid
```tsx
import { Swap } from '@ark-ui/solid/swap'
import { Volume2Icon, VolumeXIcon } from 'lucide-solid'
import { createSignal } from 'solid-js'
import styles from 'styles/swap.module.css'
export const Scale = () => {
const [swapped, setSwapped] = createSignal(false)
return (
)
}
```
#### Vue
```vue
```
#### Svelte
```svelte
```
## Guides
### How It Works
Swap renders two indicators stacked on top of each other in a 1x1 CSS grid. The `swap` prop controls which indicator is
visible. Each indicator uses the presence system, so you get `data-state="open"` and `data-state="closed"` attributes to
drive your CSS animations.
### Animating Indicators
Target `data-state` on each indicator to define enter and exit animations:
```css
.indicator[data-state='open'] {
animation: fade-in 200ms ease-out;
}
.indicator[data-state='closed'] {
animation: fade-out 100ms ease-in;
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
```
You can combine animations for richer effects. For example, scale with fade:
```css
.indicator[data-state='open'] {
animation:
scale-in 200ms ease-out,
fade-in 200ms ease-out;
}
.indicator[data-state='closed'] {
animation:
scale-out 100ms ease-in,
fade-out 100ms ease-in;
}
```
### 3D Flip Animation
For a flip effect, set `perspective` on the root and use `backface-visibility: hidden` on indicators:
```css
.flip-indicator {
backface-visibility: hidden;
}
.flip-indicator[data-state='open'] {
animation: flip-in 400ms ease;
}
.flip-indicator[data-state='closed'] {
animation: flip-out 200ms ease;
}
@keyframes flip-in {
from {
transform: rotateY(180deg);
}
to {
transform: rotateY(0deg);
}
}
@keyframes flip-out {
from {
transform: rotateY(0deg);
}
to {
transform: rotateY(180deg);
}
}
```
### Lazy Mount
Use `lazyMount` and `unmountOnExit` to control when indicators mount and unmount. This keeps the DOM clean when
indicators aren't visible.
```tsx
...
...
```
## API Reference
### Props
**Component API Reference**
#### React
**Root Props:**
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| `lazyMount` | `boolean` | No | Whether to enable lazy mounting |
| `swap` | `boolean` | No | Whether the swap is in the "on" state. |
| `unmountOnExit` | `boolean` | No | Whether to unmount on exit. |
**Indicator Props:**
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `type` | `'on' | 'off'` | Yes | |
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |
**RootProvider Props:**
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `value` | `UseSwapReturn` | Yes | |
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |
#### Solid
**Root Props:**
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `(props: ParentProps<'span'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| `lazyMount` | `boolean` | No | Whether to enable lazy mounting |
| `swap` | `boolean` | No | Whether the swap is in the "on" state. |
| `unmountOnExit` | `boolean` | No | Whether to unmount on exit. |
**Indicator Props:**
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `type` | `'on' | 'off'` | Yes | |
| `asChild` | `(props: ParentProps<'span'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. |
**RootProvider Props:**
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `value` | `Accessor` | Yes | |
| `asChild` | `(props: ParentProps<'span'>) => Element` | No | Use the provided child element as the default rendered element, combining their props and behavior. |
#### Vue
**Root Props:**
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| `lazyMount` | `boolean` | No | Whether to enable lazy mounting. |
| `swap` | `boolean` | No | Whether the swap is in the "on" state. |
| `unmountOnExit` | `boolean` | No | Whether to unmount on exit. |
**Indicator Props:**
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `type` | `'on' | 'off'` | Yes | |
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |
**RootProvider Props:**
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `value` | `UseSwapReturn` | Yes | |
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |
#### Svelte
**Root Props:**
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `Snippet<[PropsFn<'span'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| `lazyMount` | `boolean` | No | Whether to enable lazy mounting |
| `ref` | `Element` | No | |
| `swap` | `boolean` | No | Whether the swap is in the "on" state. |
| `unmountOnExit` | `boolean` | No | Whether to unmount on exit. |
**Indicator Props:**
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `type` | `'off' | 'on'` | Yes | |
| `asChild` | `Snippet<[PropsFn<'span'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| `ref` | `Element` | No | |
**RootProvider Props:**
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `value` | `Accessor` | Yes | |
| `asChild` | `Snippet<[PropsFn<'span'>]>` | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| `ref` | `Element` | No | |
### Context