UI Components Easy
Sparkles Text
Text with floating sparkle particles that animate around it, creating a magical glittering effect using positioned elements.
Open in Lab
MCP
css javascript vue svelte
Targets: TS JS HTML React Vue Svelte
Code
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: system-ui, -apple-system, sans-serif;
min-height: 100vh;
display: grid;
place-items: center;
background: #0a0a0a;
}
.container {
text-align: center;
padding: 2rem;
}
/* --- Sparkles Text --- */
.sparkles-wrapper {
position: relative;
display: inline-block;
padding: 1rem 2rem;
}
.sparkles-text {
font-size: clamp(2.5rem, 7vw, 5.5rem);
font-weight: 900;
letter-spacing: -0.03em;
line-height: 1.1;
color: #f0f0f0;
position: relative;
z-index: 1;
}
/* Individual sparkle */
.sparkle {
position: absolute;
pointer-events: none;
z-index: 2;
animation: sparkle-anim 0.8s ease-out forwards;
}
.sparkle svg {
display: block;
}
@keyframes sparkle-anim {
0% {
transform: scale(0) rotate(0deg);
opacity: 1;
}
50% {
transform: scale(1) rotate(90deg);
opacity: 1;
}
100% {
transform: scale(0) rotate(180deg);
opacity: 0;
}
}
.subtitle {
margin-top: 1.5rem;
font-size: 1rem;
color: #666;
letter-spacing: 0.01em;
position: relative;
z-index: 1;
}
/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
.sparkle {
animation: none;
display: none;
}
}// Sparkles Text — spawns sparkle particles around the text
(function () {
"use strict";
const wrapper = document.querySelector(".sparkles-wrapper");
if (!wrapper) return;
// Respect reduced motion
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (prefersReducedMotion) return;
const SPARKLE_COLORS = ["#ffd700", "#ffffff", "#00d4ff", "#ff9ff3", "#a78bfa"];
const SPARKLE_COUNT = 3; // how many to spawn each interval
const SPAWN_INTERVAL = 400; // ms between spawns
const SPARKLE_LIFETIME = 800; // ms per sparkle
function randomBetween(min, max) {
return Math.random() * (max - min) + min;
}
function createSparkle() {
const sparkle = document.createElement("span");
sparkle.classList.add("sparkle");
const size = randomBetween(10, 24);
const color = SPARKLE_COLORS[Math.floor(Math.random() * SPARKLE_COLORS.length)];
// Position randomly around the wrapper
const rect = wrapper.getBoundingClientRect();
const x = randomBetween(-20, rect.width + 20);
const y = randomBetween(-20, rect.height + 20);
sparkle.style.left = `${x}px`;
sparkle.style.top = `${y}px`;
sparkle.style.width = `${size}px`;
sparkle.style.height = `${size}px`;
// SVG star shape
sparkle.innerHTML = `
<svg viewBox="0 0 24 24" width="${size}" height="${size}" fill="${color}">
<path d="M12 0l3.09 7.26L23 8.27l-5.46 5.04L18.82 21 12 17.27 5.18 21l1.28-7.69L1 8.27l7.91-1.01z" />
</svg>
`;
wrapper.appendChild(sparkle);
// Remove after animation
setTimeout(() => {
sparkle.remove();
}, SPARKLE_LIFETIME);
}
setInterval(() => {
for (let i = 0; i < SPARKLE_COUNT; i++) {
createSparkle();
}
}, SPAWN_INTERVAL);
// Spawn initial batch
for (let i = 0; i < SPARKLE_COUNT * 2; i++) {
setTimeout(() => createSparkle(), i * 100);
}
})();<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Sparkles Text</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container">
<div class="sparkles-wrapper">
<h1 class="sparkles-text">Sparkles Text</h1>
</div>
<p class="subtitle">Floating sparkle particles around text</p>
</div>
<script src="script.js"></script>
</body>
</html>import { useEffect, useRef, useCallback } from "react";
import type { CSSProperties, ReactNode } from "react";
interface SparklesTextProps {
children: ReactNode;
colors?: string[];
sparkleCount?: number;
spawnInterval?: number;
className?: string;
}
interface Sparkle {
id: number;
x: number;
y: number;
size: number;
color: string;
}
export function SparklesText({
children,
colors = ["#ffd700", "#ffffff", "#00d4ff", "#ff9ff3", "#a78bfa"],
sparkleCount = 3,
spawnInterval = 400,
className = "",
}: SparklesTextProps) {
const wrapperRef = useRef<HTMLSpanElement>(null);
const idCounter = useRef(0);
const createSparkle = useCallback(() => {
const wrapper = wrapperRef.current;
if (!wrapper) return;
const rect = wrapper.getBoundingClientRect();
const size = Math.random() * 14 + 10;
const color = colors[Math.floor(Math.random() * colors.length)];
const x = Math.random() * (rect.width + 40) - 20;
const y = Math.random() * (rect.height + 40) - 20;
const sparkle = document.createElement("span");
sparkle.className = "sparkle-react";
sparkle.style.cssText = `
position: absolute;
left: ${x}px;
top: ${y}px;
width: ${size}px;
height: ${size}px;
pointer-events: none;
z-index: 2;
animation: sparkle-react-anim 0.8s ease-out forwards;
`;
sparkle.innerHTML = `
<svg viewBox="0 0 24 24" width="${size}" height="${size}" fill="${color}">
<path d="M12 0l3.09 7.26L23 8.27l-5.46 5.04L18.82 21 12 17.27 5.18 21l1.28-7.69L1 8.27l7.91-1.01z"/>
</svg>
`;
wrapper.appendChild(sparkle);
setTimeout(() => sparkle.remove(), 800);
}, [colors]);
useEffect(() => {
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (prefersReducedMotion) return;
// Initial burst
for (let i = 0; i < sparkleCount * 2; i++) {
setTimeout(() => createSparkle(), i * 100);
}
const interval = setInterval(() => {
for (let i = 0; i < sparkleCount; i++) {
createSparkle();
}
}, spawnInterval);
return () => clearInterval(interval);
}, [createSparkle, sparkleCount, spawnInterval]);
const wrapperStyle: CSSProperties = {
position: "relative",
display: "inline-block",
padding: "1rem 2rem",
};
return (
<>
<style>{`
@keyframes sparkle-react-anim {
0% { transform: scale(0) rotate(0deg); opacity: 1; }
50% { transform: scale(1) rotate(90deg); opacity: 1; }
100% { transform: scale(0) rotate(180deg); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
.sparkle-react { display: none !important; }
}
`}</style>
<span ref={wrapperRef} className={className} style={wrapperStyle}>
{children}
</span>
</>
);
}
// Demo usage
export default function SparklesTextDemo() {
return (
<div
style={{
minHeight: "100vh",
display: "grid",
placeItems: "center",
background: "#0a0a0a",
fontFamily: "system-ui, -apple-system, sans-serif",
textAlign: "center",
padding: "2rem",
}}
>
<div>
<SparklesText>
<h1
style={{
fontSize: "clamp(2.5rem, 7vw, 5.5rem)",
fontWeight: 900,
letterSpacing: "-0.03em",
lineHeight: 1.1,
color: "#f0f0f0",
position: "relative",
zIndex: 1,
}}
>
Sparkles Text
</h1>
</SparklesText>
<p
style={{
marginTop: "1.5rem",
color: "#666",
fontSize: "1rem",
position: "relative",
zIndex: 1,
}}
>
Floating sparkle particles around text
</p>
</div>
</div>
);
}<script setup>
import { ref, onMounted, onUnmounted } from "vue";
const props = defineProps({
colors: { type: Array, default: () => ["#ffd700", "#ffffff", "#00d4ff", "#ff9ff3", "#a78bfa"] },
sparkleCount: { type: Number, default: 3 },
spawnInterval: { type: Number, default: 400 },
});
const wrapperEl = ref(null);
let interval = null;
function createSparkle() {
if (!wrapperEl.value) return;
const rect = wrapperEl.value.getBoundingClientRect();
const size = Math.random() * 14 + 10;
const color = props.colors[Math.floor(Math.random() * props.colors.length)];
const x = Math.random() * (rect.width + 40) - 20;
const y = Math.random() * (rect.height + 40) - 20;
const sparkle = document.createElement("span");
sparkle.className = "sparkle-vue";
sparkle.style.cssText = `
position: absolute;
left: ${x}px;
top: ${y}px;
width: ${size}px;
height: ${size}px;
pointer-events: none;
z-index: 2;
animation: sparkle-vue-anim 0.8s ease-out forwards;
`;
sparkle.innerHTML = `
<svg viewBox="0 0 24 24" width="${size}" height="${size}" fill="${color}">
<path d="M12 0l3.09 7.26L23 8.27l-5.46 5.04L18.82 21 12 17.27 5.18 21l1.28-7.69L1 8.27l7.91-1.01z"/>
</svg>
`;
wrapperEl.value.appendChild(sparkle);
setTimeout(() => sparkle.remove(), 800);
}
onMounted(() => {
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (prefersReducedMotion) return;
for (let i = 0; i < props.sparkleCount * 2; i++) {
setTimeout(() => createSparkle(), i * 100);
}
interval = setInterval(() => {
for (let i = 0; i < props.sparkleCount; i++) {
createSparkle();
}
}, props.spawnInterval);
});
onUnmounted(() => {
if (interval) clearInterval(interval);
});
</script>
<template>
<div class="demo">
<div>
<span ref="wrapperEl" class="sparkle-wrapper">
<h1 class="heading">Sparkles Text</h1>
</span>
<p class="subtitle">Floating sparkle particles around text</p>
</div>
</div>
</template>
<style>
@keyframes sparkle-vue-anim {
0% { transform: scale(0) rotate(0deg); opacity: 1; }
50% { transform: scale(1) rotate(90deg); opacity: 1; }
100% { transform: scale(0) rotate(180deg); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
.sparkle-vue { display: none !important; }
}
</style>
<style scoped>
.demo {
min-height: 100vh;
display: grid;
place-items: center;
background: #0a0a0a;
font-family: system-ui, -apple-system, sans-serif;
text-align: center;
padding: 2rem;
}
.sparkle-wrapper {
position: relative;
display: inline-block;
padding: 1rem 2rem;
}
.heading {
font-size: clamp(2.5rem, 7vw, 5.5rem);
font-weight: 900;
letter-spacing: -0.03em;
line-height: 1.1;
color: #f0f0f0;
position: relative;
z-index: 1;
}
.subtitle {
margin-top: 1.5rem;
color: #666;
font-size: 1rem;
position: relative;
z-index: 1;
}
</style><script>
import { onMount, onDestroy } from "svelte";
export let colors = ["#ffd700", "#ffffff", "#00d4ff", "#ff9ff3", "#a78bfa"];
export let sparkleCount = 3;
export let spawnInterval = 400;
let wrapperEl;
let interval;
function createSparkle() {
if (!wrapperEl) return;
const rect = wrapperEl.getBoundingClientRect();
const size = Math.random() * 14 + 10;
const color = colors[Math.floor(Math.random() * colors.length)];
const x = Math.random() * (rect.width + 40) - 20;
const y = Math.random() * (rect.height + 40) - 20;
const sparkle = document.createElement("span");
sparkle.className = "sparkle-svelte";
sparkle.style.cssText = `
position: absolute;
left: ${x}px;
top: ${y}px;
width: ${size}px;
height: ${size}px;
pointer-events: none;
z-index: 2;
animation: sparkle-svelte-anim 0.8s ease-out forwards;
`;
sparkle.innerHTML = `
<svg viewBox="0 0 24 24" width="${size}" height="${size}" fill="${color}">
<path d="M12 0l3.09 7.26L23 8.27l-5.46 5.04L18.82 21 12 17.27 5.18 21l1.28-7.69L1 8.27l7.91-1.01z"/>
</svg>
`;
wrapperEl.appendChild(sparkle);
setTimeout(() => sparkle.remove(), 800);
}
onMount(() => {
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (prefersReducedMotion) return;
for (let i = 0; i < sparkleCount * 2; i++) {
setTimeout(() => createSparkle(), i * 100);
}
interval = setInterval(() => {
for (let i = 0; i < sparkleCount; i++) {
createSparkle();
}
}, spawnInterval);
});
onDestroy(() => {
if (interval) clearInterval(interval);
});
</script>
<svelte:head>
<style>
@keyframes sparkle-svelte-anim {
0% { transform: scale(0) rotate(0deg); opacity: 1; }
50% { transform: scale(1) rotate(90deg); opacity: 1; }
100% { transform: scale(0) rotate(180deg); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
.sparkle-svelte { display: none !important; }
}
</style>
</svelte:head>
<div class="demo">
<div>
<span bind:this={wrapperEl} class="sparkle-wrapper">
<h1 class="heading">Sparkles Text</h1>
</span>
<p class="subtitle">Floating sparkle particles around text</p>
</div>
</div>
<style>
.demo {
min-height: 100vh;
display: grid;
place-items: center;
background: #0a0a0a;
font-family: system-ui, -apple-system, sans-serif;
text-align: center;
padding: 2rem;
}
.sparkle-wrapper {
position: relative;
display: inline-block;
padding: 1rem 2rem;
}
.heading {
font-size: clamp(2.5rem, 7vw, 5.5rem);
font-weight: 900;
letter-spacing: -0.03em;
line-height: 1.1;
color: #f0f0f0;
position: relative;
z-index: 1;
}
.subtitle {
margin-top: 1.5rem;
color: #666;
font-size: 1rem;
position: relative;
z-index: 1;
}
</style>Sparkles Text
Text surrounded by animated sparkle particles that float, scale, and fade around the text. Creates a magical, celebratory effect perfect for highlighting special content.
How it works
- The text container has
position: relativeto anchor sparkle elements - JavaScript creates small sparkle elements (star shapes via CSS) at random positions around the text
- Each sparkle animates with
@keyframes— scaling up, rotating, and fading out - New sparkles are spawned continuously on a timer, replacing ones that have finished their animation
- Sparkle colors cycle through gold, white, and cyan for variety
Customization
--sparkle-countcontrols how many sparkles are active at once (default: 10)--sparkle-speedcontrols individual sparkle animation duration--sparkle-colorsets the primary sparkle color- Sparkle size and spread radius are randomized for organic feel
When to use it
- “New” or “Featured” labels
- Celebration messages and success states
- Magical or premium product headings
- Any text that needs to feel special and eye-catching