Buttons
SplitReveal
On hover the face splits in two, top half up and bottom half down, revealing a second label underneath. CSS only.
Download
- React
- Tailwind CSS v4
components/ui/split-reveal.tsx
import type { ReactNode } from "react";
type SplitRevealProps = {
children: ReactNode;
className?: string;
onClick?: () => void;
/** Label under the face, shown when it splits. Defaults to the same label. */
reveal?: ReactNode;
/** Face colour and its label colour. */
face?: [string, string];
/** Colour under the face and its label colour. */
under?: [string, string];
};
/* SplitReveal: on hover the face splits in two, top half up and bottom half down, revealing a second label underneath. CSS only. */
export function SplitReveal({
children,
className = "rounded-xl px-9 py-4 text-[15px] font-medium",
onClick,
reveal,
face = ["#a78bfa", "#1a1530"],
under = ["#0d0c14", "#ede9fe"],
}: SplitRevealProps) {
const half =
"pointer-events-none absolute inset-0 grid place-items-center transition-transform duration-[400ms] ease-[cubic-bezier(0.22,1,0.36,1)] motion-reduce:transition-none";
return (
<button
type="button"
onClick={onClick}
className={`group relative isolate overflow-hidden ${className}`}
style={{ background: under[0], color: under[1] }}
>
<span className="grid place-items-center">
{/* Real label: sets the size and the accessible name. The copies are hidden from screen readers. */}
<span className="[grid-area:1/1] opacity-0">{children}</span>
<span aria-hidden className="[grid-area:1/1]">
{reveal ?? children}
</span>
</span>
<span
aria-hidden
className={`${half} [clip-path:inset(0_0_50%_0)] group-hover:-translate-y-1/2 group-focus-visible:-translate-y-1/2`}
style={{ background: face[0], color: face[1] }}
>
{children}
</span>
<span
aria-hidden
className={`${half} [clip-path:inset(50%_0_0_0)] group-hover:translate-y-1/2 group-focus-visible:translate-y-1/2`}
style={{ background: face[0], color: face[1] }}
>
{children}
</span>
</button>
);
}
1. Paste the Code tab into
components/ui/split-reveal.tsx. The styles are Tailwind CSS v4 classes.2. Use it. This is the preview above:
app/split-reveal-demo.tsx
import { SplitReveal } from "@/components/ui/split-reveal"; export default function SplitRevealExample() { return ( <div className="grid h-full place-items-center bg-[radial-gradient(circle_at_50%_60%,#1d1a33,#0d0c14_70%)]"> <SplitReveal reveal="Yes, sign me up">Join the beta</SplitReveal> </div> ); }
Props
| Name | Type | Default | What it does |
|---|---|---|---|
| children | ReactNode | — | Button label. |
| onClick | () => void | — | Click handler. |
| reveal | ReactNode | same label | Label under the face. |
| face | [string, string] | ["#a78bfa", "#1a1530"] | Face colour and its label colour. |
| under | [string, string] | ["#0d0c14", "#ede9fe"] | Colour under the face and its label colour. |
| className | string | rounded block | Replaces the default look. |