UI Components Easy
Aurora Text
Text with aurora borealis colors (green, purple, blue) flowing through it with animated gradient layers and optional blur glow.
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;
overflow: hidden;
}
.container {
text-align: center;
padding: 2rem;
}
/* --- Aurora Text --- */
.aurora-wrapper {
position: relative;
display: inline-block;
}
.aurora-text {
--aurora-1: #00ff87;
--aurora-2: #7c3aed;
--aurora-3: #00d4ff;
--aurora-speed: 6s;
position: relative;
z-index: 1;
font-size: clamp(2.5rem, 7vw, 5.5rem);
font-weight: 900;
letter-spacing: -0.03em;
line-height: 1.1;
background: linear-gradient(
135deg,
var(--aurora-1) 0%,
var(--aurora-2) 33%,
var(--aurora-3) 66%,
var(--aurora-1) 100%
);
background-size: 300% 300%;
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
animation: aurora-shift var(--aurora-speed) ease-in-out infinite;
}
@keyframes aurora-shift {
0%,
100% {
background-position: 0% 50%;
}
25% {
background-position: 100% 0%;
}
50% {
background-position: 100% 100%;
}
75% {
background-position: 0% 100%;
}
}
/* Blurred glow behind text */
.aurora-glow {
position: absolute;
inset: 0;
z-index: 0;
font-size: clamp(2.5rem, 7vw, 5.5rem);
font-weight: 900;
letter-spacing: -0.03em;
line-height: 1.1;
white-space: nowrap;
background: linear-gradient(
135deg,
var(--aurora-1, #00ff87) 0%,
var(--aurora-2, #7c3aed) 33%,
var(--aurora-3, #00d4ff) 66%,
var(--aurora-1, #00ff87) 100%
);
background-size: 300% 300%;
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
filter: blur(28px) brightness(1.5);
opacity: 0.6;
animation: aurora-shift 6s ease-in-out infinite;
animation-delay: -0.5s;
pointer-events: none;
user-select: none;
}
.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) {
.aurora-text,
.aurora-glow {
animation: none;
}
}// Aurora Text — the core effect is CSS-only.
// This optional script adds a subtle canvas aurora backdrop for enhanced depth.
(function () {
"use strict";
const wrapper = document.querySelector(".aurora-wrapper");
if (!wrapper) return;
// Respect reduced motion
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (prefersReducedMotion) return;
const canvas = document.createElement("canvas");
canvas.width = 600;
canvas.height = 200;
Object.assign(canvas.style, {
position: "absolute",
inset: "0",
width: "100%",
height: "100%",
zIndex: "0",
opacity: "0.3",
pointerEvents: "none",
filter: "blur(40px)",
});
canvas.setAttribute("aria-hidden", "true");
wrapper.style.position = "relative";
wrapper.prepend(canvas);
const ctx = canvas.getContext("2d");
let t = 0;
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
const w = canvas.width;
const h = canvas.height;
// Draw flowing aurora bands
for (let i = 0; i < 3; i++) {
const offset = i * 1.2;
ctx.beginPath();
ctx.moveTo(0, h * 0.5);
for (let x = 0; x <= w; x += 4) {
const y =
h * 0.5 +
Math.sin((x / w) * Math.PI * 2 + t * 0.8 + offset) * 30 +
Math.sin((x / w) * Math.PI * 3 + t * 1.2 + offset) * 20;
ctx.lineTo(x, y);
}
ctx.lineTo(w, h);
ctx.lineTo(0, h);
ctx.closePath();
const colors = [
"rgba(0, 255, 135, 0.4)",
"rgba(124, 58, 237, 0.4)",
"rgba(0, 212, 255, 0.4)",
];
ctx.fillStyle = colors[i];
ctx.fill();
}
t += 0.015;
requestAnimationFrame(draw);
}
draw();
})();<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Aurora Text</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container">
<div class="aurora-wrapper">
<h1 class="aurora-text">Aurora Borealis</h1>
<div class="aurora-glow" aria-hidden="true">Aurora Borealis</div>
</div>
<p class="subtitle">Northern lights flowing through text</p>
</div>
<script src="script.js"></script>
</body>
</html>import { useEffect, useRef } from "react";
import type { CSSProperties, ReactNode } from "react";
interface AuroraTextProps {
children: ReactNode;
colors?: [string, string, string];
speed?: string;
className?: string;
}
export function AuroraText({
children,
colors = ["#00ff87", "#7c3aed", "#00d4ff"],
speed = "6s",
className = "",
}: AuroraTextProps) {
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (prefersReducedMotion) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
let t = 0;
let animationFrameId: number;
const defaultColors = [
"rgba(0, 255, 135, 0.4)",
"rgba(124, 58, 237, 0.4)",
"rgba(0, 212, 255, 0.4)",
];
function draw() {
ctx!.clearRect(0, 0, canvas!.width, canvas!.height);
const w = canvas!.width;
const h = canvas!.height;
// Draw flowing aurora bands
for (let i = 0; i < 3; i++) {
const offset = i * 1.2;
ctx!.beginPath();
ctx!.moveTo(0, h * 0.5);
for (let x = 0; x <= w; x += 4) {
const y =
h * 0.5 +
Math.sin((x / w) * Math.PI * 2 + t * 0.8 + offset) * 30 +
Math.sin((x / w) * Math.PI * 3 + t * 1.2 + offset) * 20;
ctx!.lineTo(x, y);
}
ctx!.lineTo(w, h);
ctx!.lineTo(0, h);
ctx!.closePath();
ctx!.fillStyle = defaultColors[i];
ctx!.fill();
}
t += 0.015;
animationFrameId = requestAnimationFrame(draw);
}
draw();
return () => {
cancelAnimationFrame(animationFrameId);
};
}, []);
const textStyle: CSSProperties = {
position: "relative",
zIndex: 1,
backgroundImage: `linear-gradient(135deg, ${colors[0]} 0%, ${colors[1]} 33%, ${colors[2]} 66%, ${colors[0]} 100%)`,
backgroundSize: "300% 300%",
WebkitBackgroundClip: "text",
backgroundClip: "text",
WebkitTextFillColor: "transparent",
animation: `aurora-shift ${speed} ease-in-out infinite`,
};
const glowStyle: CSSProperties = {
...textStyle,
position: "absolute",
inset: 0,
zIndex: 0,
filter: "blur(28px) brightness(1.5)",
opacity: 0.6,
animationDelay: "-0.5s",
pointerEvents: "none",
userSelect: "none",
};
return (
<>
<style>{`
@keyframes aurora-shift {
0%, 100% { background-position: 0% 50%; }
25% { background-position: 100% 0%; }
50% { background-position: 100% 100%; }
75% { background-position: 0% 100%; }
}
@media (prefers-reduced-motion: reduce) {
.aurora-text-component, .aurora-glow-component { animation: none !important; }
}
`}</style>
<span style={{ position: "relative", display: "inline-block" }}>
<canvas
ref={canvasRef}
width={600}
height={200}
style={{
position: "absolute",
inset: 0,
width: "100%",
height: "100%",
zIndex: 0,
opacity: 0.3,
pointerEvents: "none",
filter: "blur(40px)",
}}
aria-hidden="true"
/>
<span className={`aurora-glow-component ${className}`} style={glowStyle} aria-hidden="true">
{children}
</span>
<span className={`aurora-text-component ${className}`} style={textStyle}>
{children}
</span>
</span>
</>
);
}
// Demo usage
export default function AuroraTextDemo() {
return (
<div
style={{
minHeight: "100vh",
display: "grid",
placeItems: "center",
background: "#0a0a0a",
fontFamily: "system-ui, -apple-system, sans-serif",
textAlign: "center",
padding: "2rem",
}}
>
<div>
<h1
style={{
fontSize: "clamp(2.5rem, 7vw, 5.5rem)",
fontWeight: 900,
letterSpacing: "-0.03em",
lineHeight: 1.1,
}}
>
<AuroraText>Aurora Borealis</AuroraText>
</h1>
<p
style={{
marginTop: "1.5rem",
color: "#666",
fontSize: "1rem",
position: "relative",
zIndex: 1,
}}
>
Northern lights flowing through text
</p>
</div>
</div>
);
}<script setup lang="ts">
import { onMounted, onUnmounted, ref } from "vue";
const props = withDefaults(
defineProps<{
colors?: [string, string, string];
speed?: string;
}>(),
{
colors: () => ["#00ff87", "#7c3aed", "#00d4ff"],
speed: "6s",
}
);
const canvasRef = ref<HTMLCanvasElement | null>(null);
let animationFrameId = 0;
onMounted(() => {
const canvas = canvasRef.value;
if (!canvas) return;
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (prefersReducedMotion) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
let t = 0;
const defaultColors = [
"rgba(0, 255, 135, 0.4)",
"rgba(124, 58, 237, 0.4)",
"rgba(0, 212, 255, 0.4)",
];
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
const w = canvas.width;
const h = canvas.height;
for (let i = 0; i < 3; i++) {
const offset = i * 1.2;
ctx.beginPath();
ctx.moveTo(0, h * 0.5);
for (let x = 0; x <= w; x += 4) {
const y =
h * 0.5 +
Math.sin((x / w) * Math.PI * 2 + t * 0.8 + offset) * 30 +
Math.sin((x / w) * Math.PI * 3 + t * 1.2 + offset) * 20;
ctx.lineTo(x, y);
}
ctx.lineTo(w, h);
ctx.lineTo(0, h);
ctx.closePath();
ctx.fillStyle = defaultColors[i];
ctx.fill();
}
t += 0.015;
animationFrameId = requestAnimationFrame(draw);
}
draw();
});
onUnmounted(() => {
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
}
});
</script>
<template>
<div style="min-height:100vh;display:grid;place-items:center;background:#0a0a0a;font-family:system-ui,-apple-system,sans-serif;text-align:center;padding:2rem">
<div>
<h1 style="font-size:clamp(2.5rem,7vw,5.5rem);font-weight:900;letter-spacing:-0.03em;line-height:1.1">
<span style="position:relative;display:inline-block">
<canvas ref="canvasRef" width="600" height="200" style="position:absolute;inset:0;width:100%;height:100%;z-index:0;opacity:0.3;pointer-events:none;filter:blur(40px)"></canvas>
<span class="aurora-glow" :style="{
position:'absolute',inset:0,zIndex:0,filter:'blur(28px) brightness(1.5)',opacity:0.6,animationDelay:'-0.5s',pointerEvents:'none',userSelect:'none',
backgroundImage:`linear-gradient(135deg,${props.colors[0]} 0%,${props.colors[1]} 33%,${props.colors[2]} 66%,${props.colors[0]} 100%)`,
backgroundSize:'300% 300%',WebkitBackgroundClip:'text',backgroundClip:'text',WebkitTextFillColor:'transparent',
animation:`aurora-shift ${props.speed} ease-in-out infinite`
}" aria-hidden="true">Aurora Borealis</span>
<span class="aurora-text" :style="{
position:'relative',zIndex:1,
backgroundImage:`linear-gradient(135deg,${props.colors[0]} 0%,${props.colors[1]} 33%,${props.colors[2]} 66%,${props.colors[0]} 100%)`,
backgroundSize:'300% 300%',WebkitBackgroundClip:'text',backgroundClip:'text',WebkitTextFillColor:'transparent',
animation:`aurora-shift ${props.speed} ease-in-out infinite`
}">Aurora Borealis</span>
</span>
</h1>
<p style="margin-top:1.5rem;color:#666;font-size:1rem;position:relative;z-index:1">Northern lights flowing through text</p>
</div>
</div>
</template>
<style scoped>
@keyframes aurora-shift {
0%, 100% { background-position: 0% 50%; }
25% { background-position: 100% 0%; }
50% { background-position: 100% 100%; }
75% { background-position: 0% 100%; }
}
@media (prefers-reduced-motion: reduce) {
.aurora-text, .aurora-glow { animation: none !important; }
}
</style><script>
import { onMount } from "svelte";
export let colors = ["#00ff87", "#7c3aed", "#00d4ff"];
export let speed = "6s";
let canvasRef;
onMount(() => {
const canvas = canvasRef;
if (!canvas) return;
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (prefersReducedMotion) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
let t = 0;
let animationFrameId;
const defaultColors = [
"rgba(0, 255, 135, 0.4)",
"rgba(124, 58, 237, 0.4)",
"rgba(0, 212, 255, 0.4)",
];
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
const w = canvas.width;
const h = canvas.height;
for (let i = 0; i < 3; i++) {
const offset = i * 1.2;
ctx.beginPath();
ctx.moveTo(0, h * 0.5);
for (let x = 0; x <= w; x += 4) {
const y =
h * 0.5 +
Math.sin((x / w) * Math.PI * 2 + t * 0.8 + offset) * 30 +
Math.sin((x / w) * Math.PI * 3 + t * 1.2 + offset) * 20;
ctx.lineTo(x, y);
}
ctx.lineTo(w, h);
ctx.lineTo(0, h);
ctx.closePath();
ctx.fillStyle = defaultColors[i];
ctx.fill();
}
t += 0.015;
animationFrameId = requestAnimationFrame(draw);
}
draw();
return () => {
cancelAnimationFrame(animationFrameId);
};
});
</script>
<div style="min-height:100vh;display:grid;place-items:center;background:#0a0a0a;font-family:system-ui,-apple-system,sans-serif;text-align:center;padding:2rem">
<div>
<h1 style="font-size:clamp(2.5rem,7vw,5.5rem);font-weight:900;letter-spacing:-0.03em;line-height:1.1">
<span style="position:relative;display:inline-block">
<canvas bind:this={canvasRef} width="600" height="200" style="position:absolute;inset:0;width:100%;height:100%;z-index:0;opacity:0.3;pointer-events:none;filter:blur(40px)"></canvas>
<span class="aurora-glow" style="position:absolute;inset:0;z-index:0;filter:blur(28px) brightness(1.5);opacity:0.6;animation-delay:-0.5s;pointer-events:none;user-select:none;background-image:linear-gradient(135deg,{colors[0]} 0%,{colors[1]} 33%,{colors[2]} 66%,{colors[0]} 100%);background-size:300% 300%;-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;animation:aurora-shift {speed} ease-in-out infinite" aria-hidden="true">Aurora Borealis</span>
<span class="aurora-text" style="position:relative;z-index:1;background-image:linear-gradient(135deg,{colors[0]} 0%,{colors[1]} 33%,{colors[2]} 66%,{colors[0]} 100%);background-size:300% 300%;-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;animation:aurora-shift {speed} ease-in-out infinite">Aurora Borealis</span>
</span>
</h1>
<p style="margin-top:1.5rem;color:#666;font-size:1rem;position:relative;z-index:1">Northern lights flowing through text</p>
</div>
</div>
<style>
@keyframes aurora-shift {
0%, 100% { background-position: 0% 50%; }
25% { background-position: 100% 0%; }
50% { background-position: 100% 100%; }
75% { background-position: 0% 100%; }
}
@media (prefers-reduced-motion: reduce) {
.aurora-text, .aurora-glow { animation: none !important; }
}
</style>Aurora Text
Text that shimmers with northern-lights colors — green, purple, and blue gradients that flow and blend organically through the text.
How it works
- Multiple animated gradients are layered using
background-clip: text - Each gradient layer animates at a different speed and direction for organic movement
- A blurred pseudo-element behind the text creates a soft ambient glow
- Colors are inspired by the aurora borealis: emerald green, violet purple, and cyan blue
Customization
- Override aurora colors via
--aurora-1,--aurora-2,--aurora-3CSS custom properties - Control glow intensity with
--aurora-glow(blur radius of the backdrop) - Adjust animation speed with
--aurora-speed
When to use it
- Dark-themed hero sections
- Feature headings that need an ethereal, premium feel
- Creative portfolio titles