BackgroundMeteors
Meteors
A simple meteor shower effect using Tailwind CSS and React.
Preview
Code
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {
keyframes: {
// ...
meteor: {
"0%": { transform: "rotate(215deg) translateX(0)", opacity: "0" },
"70%": { opacity: "100%" },
"100%": {
transform: "rotate(215deg) translateX(-500px)",
opacity: "",
},
},
},
animation: {
// ...
meteor: "meteor 0.2s linear infinite",
},
},
},
plugins: [],
};
"use client";
import React, { useEffect, useState } from "react";
import clsx from "clsx";
import { twMerge } from "tailwind-merge";
const cn = (...args: any[]) => {
return clsx(twMerge(...args));
};
interface MeteorsProps {
number?: number;
}
export const Meteors = ({ number = 20 }: MeteorsProps) => {
const [meteorStyles, setMeteorStyles] = useState<Array<React.CSSProperties>>(
[],
);
useEffect(() => {
const styles = [...new Array(number)].map(() => ({
top: -5,
left: Math.floor(Math.random() * window.innerWidth) + "px",
animationDelay: Math.random() * 1 + 0.2 + "s",
animationDuration: Math.floor(Math.random() * 8 + 2) + "s",
}));
setMeteorStyles(styles);
}, [number]);
return (
<>
{[...meteorStyles].map((style, idx) => (
<span
key={idx}
className={cn(
"pointer-events-none absolute left-1/2 top-1/2 h-0.5 w-0.5 rotate-[215deg] animate-meteor rounded-[9999px] bg-white shadow-[0_0_90px_10px_#ffffff10]",
)}
style={style}
>
<div className="pointer-events-none absolute top-1/2 -z-10 h-[1px] w-[50px] -translate-y-1/2 bg-gradient-to-r from-slate-500 to-transparent" />
</span>
))}
</>
);
};
Usage
import { Meteors } from "@/components/library/general/Meteors";
export default function MeteorsPage() {
return (
<div>
<Meteors number={20} />
</div>
);
}
Props
Prop | Type | Default |
---|---|---|
number | number | - |
Edit on GitHub
Last updated on