Buttons
FlipAction
On hover or focus the whole button flips over in 3D and shows its back face. Reduced motion cross-fades instead.
Download
- React
- Tailwind CSS v4
- motion
components/ui/flip-action.tsx
"use client";
import { useState, type ReactNode } from "react";
import { motion, useReducedMotion } from "motion/react";
type FlipActionProps = {
children: ReactNode;
className?: string;
onClick?: () => void;
/** Content on the back face. Defaults to the same label. */
back?: ReactNode;
/** Look of the back face. */
backClassName?: string;
};
/* FlipAction: on hover or focus the whole button flips over in 3D and shows its back face. */
export function FlipAction({
children,
className = "rounded-full border border-[#a78bfa]/50 bg-[#1a1530] px-9 py-4 text-[15px] font-medium text-[#ede9fe]",
onClick,
back,
backClassName = "rounded-full bg-[#a78bfa] px-9 py-4 text-[15px] font-medium text-[#1a1530]",
}: FlipActionProps) {
const reduce = useReducedMotion();
const [on, setOn] = useState(false);
const face = "[grid-area:1/1] grid place-items-center [backface-visibility:hidden]";
return (
<button
type="button"
onClick={onClick}
onPointerEnter={() => setOn(true)}
onPointerLeave={() => setOn(false)}
onFocus={() => setOn(true)}
onBlur={() => setOn(false)}
className="rounded-full [perspective:700px]"
>
<motion.span
className="grid [transform-style:preserve-3d]"
initial={false}
animate={{ rotateX: on && !reduce ? 180 : 0 }}
transition={{ type: "spring", visualDuration: 0.5, bounce: 0.3 }}
>
{/* Reduced motion: the faces cross-fade instead of flipping. */}
<motion.span className={`${face} ${className}`} initial={false} animate={{ opacity: reduce && on ? 0 : 1 }}>
{children}
</motion.span>
<motion.span
aria-hidden
className={`${face} ${backClassName}`}
style={{ rotateX: reduce ? 0 : 180 }}
initial={false}
animate={{ opacity: reduce && !on ? 0 : 1 }}
>
{back ?? children}
</motion.span>
</motion.span>
</button>
);
}
1. Install the dependency.
npm i motion2. Paste the Code tab into
components/ui/flip-action.tsx. The styles are Tailwind CSS v4 classes.3. Use it. This is the preview above:
app/flip-action-demo.tsx
import { FlipAction } from "@/components/ui/flip-action"; export default function FlipActionExample() { return ( <div className="grid h-full place-items-center bg-[radial-gradient(circle_at_50%_60%,#1d1a33,#0d0c14_70%)]"> <FlipAction back="Let's go →">Start free trial</FlipAction> </div> ); }
Props
| Name | Type | Default | What it does |
|---|---|---|---|
| children | ReactNode | — | Button label. |
| onClick | () => void | — | Click handler. |
| back | ReactNode | same label | Content on the back face. |
| backClassName | string | violet pill | Look of the back face. |
| className | string | dark outline pill | Replaces the default look. |