Text animations
Reveal Text
A vertical reveal text effect. Detects whether the mouse enters from the top or bottom and slides a colored text shadow in from that direction.
Installation
CLI (Recommended)
npx shadcn@latest add https://satisui.xyz/r/reveal-text.jsonManual
No third-party dependencies are required. Copy the following code into components/satisui/reveal-text.tsx.
import React, { useRef, CSSProperties, MouseEvent } from 'react';
/**
* Props for the RevealText component.
*/
interface RevealTextProps {
/** The text content to display and animate. */
text: string;
/** The primary color of the text in its resting state. Defaults to #ffffff. */
color?: string;
/** The color of the text that slides in on hover. Defaults to #00ffcc. */
revealColor?: string;
/** Optional CSS classes for the container (e.g., font size, margin). */
className?: string;
}
interface VerticalStyle extends CSSProperties {
'--text-clr'?: string;
'--clr'?: string;
'--dir-y'?: number;
'--travel-dist'?: string;
}
/**
* A vertical reveal text effect.
* Detects whether the mouse enters from the top or bottom and slides
* a colored text shadow in from that direction.
*/
const RevealText: React.FC<RevealTextProps> = ({
text,
color = '#ffffff',
revealColor = '#00ffcc',
className = 'text-4xl',
}) => {
const containerRef = useRef<HTMLDivElement>(null);
const handleMouseEnter = (e: MouseEvent<HTMLDivElement>) => {
if (!containerRef.current) return;
const rect = containerRef.current.getBoundingClientRect();
const centerY = rect.top + rect.height / 2;
// Determine direction: 1 (down) if entering from top, -1 (up) if entering from bottom
const direction = e.clientY < centerY ? 1 : -1;
containerRef.current.style.setProperty('--dir-y', direction.toString());
};
const containerStyle: VerticalStyle = {
'--text-clr': color,
'--clr': revealColor,
'--dir-y': 1,
// Using 1.2em instead of 1em ensures the text shadow is pushed
// slightly past the container edge, preventing sub-pixel bleeding at rest.
'--travel-dist': '1.2em',
color: color,
};
const spanStyle: VerticalStyle = {
textShadow:
'0px calc(var(--dir-y) * var(--travel-dist) * -1) 0px var(--clr)',
color: 'var(--text-clr)',
};
return (
<div
ref={containerRef}
className={`group inline-block relative overflow-hidden leading-tight cursor-default ${className}`}
style={containerStyle}
onMouseEnter={handleMouseEnter}
>
<span
className='
block will-change-transform
transition-transform duration-300 ease-out
group-hover:translate-y-[calc(var(--dir-y)*var(--travel-dist))]
'
style={spanStyle}
>
{text}
</span>
</div>
);
};
export default RevealText;Usage
Import the component and customize the text, colors, and styling as needed.
import RevealText from '@/components/reveal-text';
export default function RevealTextDemo() {
return (
<div className='flex flex-col items-center justify-center gap-12 min-h-[300px] bg-neutral-950 p-8'>
{/* Basic Usage with defaults */}
<RevealText text='Hover Me' />
{/* Customized Usage for Headlines */}
<RevealText
text='Design Engineering'
className='text-6xl font-bold tracking-tighter'
color='#e5e5e5'
revealColor='#fbbf24' // Amber
/>
</div>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
text | string | Required | The text content to display and animate. |
color | string | '#ffffff' | The primary color of the text in its resting state. |
revealColor | string | '#00ffcc' | The color of the text that slides in on hover. |
className | string | 'text-4xl' | Optional CSS classes for the container. |