Dashral Pro is hereSee pricing

Dashral

SwapNew

Content that changes in place: the old one fades out as the new one arrives, as a fade, a rise or a pop.

$ pnpm dlx shadcn@latest add @dashral/swap

Installation

$ pnpm dlx shadcn@latest add @dashral/swap

Adds the component, the components it builds on, its npm packages and the theme tokens it uses. Or by its full URL: https://dashral.com/r/swap.json

When to use

  • Content that changes in place after an action: an icon turning into a check, a label going from Copy to Copied, a form giving way to a thank-you.

When not to use

  • Content that appears or disappears, pushing what's below: Reveal.
  • A number that counts to its new value: MetricCard, or Badge in the Motion edition.

Usage

value is what it shows now; when it changes, the old content leaves as the new one arrives.

example.tsx
"use client"

import { useState } from "react"
import { Check, Copy } from "lucide-react"
import { Button } from "@/components/dashral/button"
import { Swap } from "@/components/dashral/swap"

export default function CopyButton() {
  const [copied, setCopied] = useState(false)

  return (
    <Button variant="outline" onClick={() => setCopied(true)}>
      <Swap value={copied} effect="pop">
        {copied ? <Check /> : <Copy />}
      </Swap>
      {copied ? "Copied" : "Copy"}
    </Button>
  )
}

Using the npm package? Import from @dashral/ui/components/swap instead, here and in the examples; the rest is the same.

API reference

Swap

PropTypeDefault
valuestring | number | boolean

Required. What it shows now, as a key: a change swaps the old content out and the new one in.

—
childrenReactNode

The content for this value.

—
effect"fade" | "rise" | "pop"

How the new content arrives: fading, rising a few pixels (text, forms) or popping in from small (an icon such as a check).

"fade"
waitboolean

The old content leaves before the new one comes, rather than both at once.

false
appearboolean

The first content arrives with the effect too, as it's added.

false
as"span" | "div"

The element: span inside a line or a button, div for blocks.

"span"
classNamestring

Classes of each content's own element, e.g. its layout.

—

Accessibility

  • The content on its way out is hidden from screen readers (aria-hidden) and can't be clicked, so only the new one is read and used.

Motion

  • The old content fades out fast (--duration-fast, --ease-exit) while the new one arrives (--duration-standard, --ease-enter), both in the same place, so nothing blinks.
  • With reduced motion they only cross-fade.