Glow Tile
A near-black app-icon tile with an aurora glow rising from the bottom — four stacked inset shadows plus an outer bloom. Recolors from one variable; scales to any size.
hover to lift & brighten · every shadow scales with size
Usage
import { GlowTile } from "~/components/glow/glow-tile";<GlowTile color="#2F6BFF" size={240} bloom intensity={1} radius={80}><Icon className="size-16 text-white/90" /></GlowTile>
How the glow works
The tile is a dark vertical gradient with no glowing element inside — the light is faked entirely with inset shadows. An inset shadow with a negative Y offset paints its color along the bottom inner edge, so a stack of them builds a glow that rises from the floor of the tile.
Four layers do it: a deep saturated base (big blur, big negative spread), a lighter mid tone, a hot white core for the bright lip, and a faint top-edge tint. An outer bloom and a dark ambient shadow sit underneath for the halo. Every offset, blur, and spread is multiplied by --u (size / 400), so the whole effect scales cleanly, and all the hues are mixed from a single --glow-color.
.glow-tile {--glow-size: 240; /* unitless → × 1px */--glow-color: #2f6bff;--u: calc(var(--glow-size) / 400); /* scale unit */--glow-deep: color-mix(in srgb, var(--glow-color) 90%, #000);--glow-soft: color-mix(in srgb, var(--glow-color) 55%, #fff);width: calc(var(--glow-size) * 1px);height: calc(var(--glow-size) * 1px);border-radius: calc(80px * var(--u));background: linear-gradient(180deg, #0a0909, #09101f);box-shadow:/* outer bloom + ambient */0 calc(22px*var(--u)) calc(70px*var(--u)) calc(-12px*var(--u))color-mix(in srgb, var(--glow-color) 45%, transparent),0 calc(10px*var(--u)) calc(28px*var(--u)) calc(-6px*var(--u)) rgba(0,0,0,.55),/* inner: top edge → white core → mid → deep base */inset 0 calc(6px*var(--u)) calc(6px*var(--u)) calc(-2px*var(--u))color-mix(in srgb, var(--glow-color) 60%, transparent),inset 0 calc(-20px*var(--u)) calc(20px*var(--u)) calc(-6px*var(--u)) rgba(255,255,255,.4),inset 0 calc(-40px*var(--u)) calc(30px*var(--u)) calc(-8px*var(--u))color-mix(in srgb, var(--glow-soft) 50%, transparent),inset 0 calc(-80px*var(--u)) calc(60px*var(--u)) calc(-30px*var(--u)) var(--glow-deep);}
Props
| prop | type | default | description |
|---|---|---|---|
| color | string | "#2F6BFF" | Glow hue; deep/mid/bloom all derive from it. |
| size | number | 240 | Tile width = height in px; shadow geometry scales with it. |
| bloom | boolean | true | Show the outer bloom + ambient halo. |
| intensity | number | 1 | Inner glow strength multiplier (≈0.4–1.4). |
| radius | number | 80 | Corner radius in 400-space (scales with size). |
| children | ReactNode | — | Centered contents (e.g. an icon). |
| …props | HTMLAttributes | — | Any native div prop (className, style, …). |
Source
download .zipThe full implementation, across 2 files. Copy it in or grab the zip. It leans on a cn() class helper and the theme tokens (--primary, --border, …).
import { cn } from "~/lib/utils";export interface GlowTilePropsextends React.HTMLAttributes<HTMLDivElement> {/** Glow hue; the deep, mid, and bloom layers all derive from it. Default #2F6BFF. */color?: string;/** Tile size in px (width = height). Shadow geometry scales with it. Default 240. */size?: number;/** Show the outer bloom + ambient halo. Default true. */bloom?: boolean;/** Inner glow strength multiplier (≈0.4–1.4). Default 1. */intensity?: number;/** Corner radius in 400-space (scales with size). Default 80. */radius?: number;}/*** A near-black "app icon" tile with a colored glow rising from the bottom edge.* The glow is four stacked inset shadows — deep base, lighter mid, a hot white* core, and a subtle top edge — plus an outer bloom. Every shadow value scales* off `--u` (size / 400) so the look holds at any size, and the whole thing* recolors from a single `--glow-color`. Styling lives in `.glow-tile`* (app.css); no Tailwind required.*/export function GlowTile({color,size,bloom,intensity,radius,className,style,...props}: GlowTileProps) {const vars = { ...style } as Record<string, string>;if (color) vars["--glow-color"] = color;if (size != null) vars["--glow-size"] = `${size}`;if (bloom != null) vars["--glow-bloom"] = bloom ? "1" : "0";if (intensity != null) vars["--glow-intensity"] = `${intensity}`;if (radius != null) vars["--glow-radius"] = `${radius}`;return (<divclassName={cn("glow-tile", className)}style={vars as React.CSSProperties}{...props}/>);}
/* ─── Glow tile (aurora icon) ──────────────────────────────────────── *//* A near-black tile with a colored glow rising from the bottom edge, builtfrom four stacked inset shadows. Every value scales off --u (= size / 400),so the look holds at any size, and the hue derives from --glow-color. */.glow-tile {--glow-size: 240; /* unitless number — multiplied by 1px below */--glow-color: #2f6bff;--glow-bloom: 1; /* 0 hides the outer bloom + ambient */--glow-intensity: 1; /* scales the inner glow strength */--glow-radius: 80; /* corner radius in 400-space (× --u) */--u: calc(var(--glow-size) / 400);--glow-deep: color-mix(in srgb, var(--glow-color) 90%, #000);--glow-soft: color-mix(in srgb, var(--glow-color) 55%, #fff);display: inline-flex;align-items: center;justify-content: center;width: calc(var(--glow-size) * 1px);height: calc(var(--glow-size) * 1px);border-radius: calc(var(--glow-radius) * var(--u) * 1px);background: linear-gradient(180deg, #0a0909, #09101f);box-shadow:/* outer bloom + ambient (gated by --glow-bloom) */0 calc(24px * var(--u)) calc(75px * var(--u)) calc(-10px * var(--u))color-mix(in srgb, var(--glow-color) calc(60% * var(--glow-bloom)), transparent),0 calc(10px * var(--u)) calc(28px * var(--u)) calc(-6px * var(--u))color-mix(in srgb, #000 calc(55% * var(--glow-bloom)), transparent),/* 4. subtle top inner edge */inset 0 calc(6px * var(--u)) calc(6px * var(--u)) calc(-2px * var(--u))color-mix(in srgb, var(--glow-color) 60%, transparent),/* 3. hot white core near the bottom (front-most) */inset 0 calc(-22px * var(--u)) calc(22px * var(--u)) calc(-6px * var(--u))color-mix(in srgb, #fff calc(min(100%, 60% * var(--glow-intensity))), transparent),/* 2. lighter mid glow */inset 0 calc(-44px * var(--u)) calc(34px * var(--u)) calc(-8px * var(--u))color-mix(in srgb, var(--glow-soft) calc(min(100%, 78% * var(--glow-intensity))), transparent),/* 1. deep saturated base glow (back-most) */inset 0 calc(-90px * var(--u)) calc(66px * var(--u)) calc(-24px * var(--u))color-mix(in srgb, var(--glow-deep) calc(min(100%, 100% * var(--glow-intensity))), transparent);transition:transform 0.25s cubic-bezier(0.2, 0.7, 0.2, 1),box-shadow 0.25s ease,filter 0.25s ease;}.glow-tile:hover {transform: translateY(calc(-4px * var(--u)));filter: brightness(1.08) saturate(1.05);}@media (prefers-reduced-motion: reduce) {.glow-tile {transition: none;}}