UI Components Easy
Dot Pattern
A repeating dot pattern background using radial-gradient, fully customizable via CSS custom properties for spacing, radius, and color.
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;
background: #000;
}
/* --- Dot pattern container --- */
.dot-pattern {
--dot-spacing: 24px;
--dot-radius: 1px;
--dot-color: rgba(255, 255, 255, 0.15);
--dot-bg: #0a0a0a;
position: relative;
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
background-color: var(--dot-bg);
background-image: radial-gradient(
circle,
var(--dot-color) var(--dot-radius),
transparent var(--dot-radius)
);
background-size: var(--dot-spacing) var(--dot-spacing);
overflow: hidden;
}
/* Radial vignette fade */
.dot-fade {
position: absolute;
inset: 0;
background: radial-gradient(ellipse 70% 50% at 50% 50%, transparent 20%, var(--dot-bg) 100%);
pointer-events: none;
}
/* --- Centered content --- */
.dot-content {
position: relative;
z-index: 1;
text-align: center;
max-width: 480px;
padding: 2rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
}
.dot-icon {
color: #6366f1;
margin-bottom: 0.5rem;
opacity: 0.8;
}
.dot-title {
font-size: 2.5rem;
font-weight: 800;
letter-spacing: -0.03em;
line-height: 1.1;
color: #fafafa;
}
.dot-description {
font-size: 1rem;
line-height: 1.7;
color: #71717a;
max-width: 380px;
}
.dot-description code {
font-family: "Fira Code", monospace;
font-size: 0.9em;
background: rgba(255, 255, 255, 0.08);
padding: 0.1em 0.4em;
border-radius: 0.3em;
color: #a5b4fc;
}
.dot-tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-top: 0.5rem;
}
.dot-tag {
font-size: 0.75rem;
font-weight: 500;
padding: 0.25rem 0.75rem;
border-radius: 999px;
background: rgba(99, 102, 241, 0.1);
border: 1px solid rgba(99, 102, 241, 0.2);
color: #a5b4fc;
letter-spacing: 0.02em;
}// Dot Pattern — CSS-only effect; no JS required.
// This script adds an optional hover-responsive glow that follows the cursor.
(function () {
"use strict";
const container = document.querySelector(".dot-pattern");
if (!container) return;
// Create a subtle glow element that follows the mouse
const glow = document.createElement("div");
Object.assign(glow.style, {
position: "absolute",
width: "500px",
height: "500px",
borderRadius: "50%",
background: "radial-gradient(circle, rgba(99,102,241,0.08) 0%, transparent 70%)",
pointerEvents: "none",
transform: "translate(-50%, -50%)",
transition: "opacity 0.3s ease",
opacity: "0",
zIndex: "0",
});
container.appendChild(glow);
container.addEventListener("mousemove", (e) => {
const rect = container.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
glow.style.left = x + "px";
glow.style.top = y + "px";
glow.style.opacity = "1";
});
container.addEventListener("mouseleave", () => {
glow.style.opacity = "0";
});
})();<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Dot Pattern</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="dot-pattern">
<div class="dot-fade"></div>
<div class="dot-content">
<div class="dot-icon">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="1"/>
<circle cx="12" cy="5" r="1"/>
<circle cx="12" cy="19" r="1"/>
<circle cx="5" cy="12" r="1"/>
<circle cx="19" cy="12" r="1"/>
<circle cx="5" cy="5" r="1"/>
<circle cx="19" cy="5" r="1"/>
<circle cx="5" cy="19" r="1"/>
<circle cx="19" cy="19" r="1"/>
</svg>
</div>
<h1 class="dot-title">Dot Pattern</h1>
<p class="dot-description">
Repeating dot background using <code>radial-gradient</code>, fully
customizable with CSS custom properties.
</p>
<div class="dot-tags">
<span class="dot-tag">CSS</span>
<span class="dot-tag">radial-gradient</span>
<span class="dot-tag">pattern</span>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>import { type CSSProperties, type ReactNode, useCallback, useRef, useState } from "react";
interface DotPatternProps {
/** Distance between dot centers in pixels */
spacing?: number;
/** Dot radius in pixels */
radius?: number;
/** Dot fill color */
color?: string;
/** Background color behind the dots */
bg?: string;
/** Extra CSS class names */
className?: string;
/** Overlay children on top of the pattern */
children?: ReactNode;
}
export function DotPattern({
spacing = 24,
radius = 1,
color = "rgba(255,255,255,0.15)",
bg = "#0a0a0a",
className = "",
children,
}: DotPatternProps) {
const containerRef = useRef<HTMLDivElement>(null);
const [glowPos, setGlowPos] = useState({ x: 0, y: 0, visible: false });
const handleMouseMove = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
const rect = e.currentTarget.getBoundingClientRect();
setGlowPos({
x: e.clientX - rect.left,
y: e.clientY - rect.top,
visible: true,
});
}, []);
const handleMouseLeave = useCallback(() => {
setGlowPos((prev) => ({ ...prev, visible: false }));
}, []);
const containerStyle: CSSProperties = {
position: "relative",
width: "100%",
minHeight: "100vh",
display: "grid",
placeItems: "center",
backgroundColor: bg,
backgroundImage: `radial-gradient(circle, ${color} ${radius}px, transparent ${radius}px)`,
backgroundSize: `${spacing}px ${spacing}px`,
overflow: "hidden",
};
const fadeStyle: CSSProperties = {
position: "absolute",
inset: 0,
background: `radial-gradient(ellipse 70% 50% at 50% 50%, transparent 20%, ${bg} 100%)`,
pointerEvents: "none",
};
const glowStyle: CSSProperties = {
position: "absolute",
width: 500,
height: 500,
borderRadius: "50%",
background: "radial-gradient(circle, rgba(99,102,241,0.08) 0%, transparent 70%)",
pointerEvents: "none",
transform: "translate(-50%, -50%)",
transition: "opacity 0.3s ease",
opacity: glowPos.visible ? 1 : 0,
left: glowPos.x,
top: glowPos.y,
zIndex: 0,
};
const contentStyle: CSSProperties = {
position: "relative",
zIndex: 1,
};
return (
<div
ref={containerRef}
className={className}
style={containerStyle}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
>
<div style={fadeStyle} />
<div style={glowStyle} />
<div style={contentStyle}>{children}</div>
</div>
);
}
// Demo usage
export default function DotPatternDemo() {
return (
<DotPattern spacing={24} radius={1} color="rgba(255,255,255,0.15)">
<div
style={{
textAlign: "center",
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: "1rem",
padding: "2rem",
}}
>
<svg
width="48"
height="48"
viewBox="0 0 24 24"
fill="none"
stroke="#6366f1"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
style={{ opacity: 0.8 }}
>
<circle cx="12" cy="12" r="1" />
<circle cx="12" cy="5" r="1" />
<circle cx="12" cy="19" r="1" />
<circle cx="5" cy="12" r="1" />
<circle cx="19" cy="12" r="1" />
<circle cx="5" cy="5" r="1" />
<circle cx="19" cy="5" r="1" />
<circle cx="5" cy="19" r="1" />
<circle cx="19" cy="19" r="1" />
</svg>
<h1
style={{
fontSize: "2.5rem",
fontWeight: 800,
letterSpacing: "-0.03em",
lineHeight: 1.1,
color: "#fafafa",
fontFamily: "system-ui, -apple-system, sans-serif",
}}
>
Dot Pattern
</h1>
<p
style={{
fontSize: "1rem",
lineHeight: 1.7,
color: "#71717a",
maxWidth: 380,
fontFamily: "system-ui, -apple-system, sans-serif",
}}
>
Repeating dot background using radial-gradient, fully customizable with CSS custom
properties.
</p>
<div style={{ display: "flex", gap: "0.5rem", marginTop: "0.5rem" }}>
{["CSS", "radial-gradient", "pattern"].map((tag) => (
<span
key={tag}
style={{
fontSize: "0.75rem",
fontWeight: 500,
padding: "0.25rem 0.75rem",
borderRadius: "999px",
background: "rgba(99,102,241,0.1)",
border: "1px solid rgba(99,102,241,0.2)",
color: "#a5b4fc",
}}
>
{tag}
</span>
))}
</div>
</div>
</DotPattern>
);
}<script setup>
import { ref } from "vue";
const props = defineProps({
spacing: { type: Number, default: 24 },
radius: { type: Number, default: 1 },
color: { type: String, default: "rgba(255,255,255,0.15)" },
bg: { type: String, default: "#0a0a0a" },
});
const glowX = ref(0);
const glowY = ref(0);
const glowVisible = ref(false);
function handleMouseMove(e) {
const rect = e.currentTarget.getBoundingClientRect();
glowX.value = e.clientX - rect.left;
glowY.value = e.clientY - rect.top;
glowVisible.value = true;
}
function handleMouseLeave() {
glowVisible.value = false;
}
const tags = ["CSS", "radial-gradient", "pattern"];
</script>
<template>
<div
class="dot-container"
:style="{
backgroundColor: bg,
backgroundImage: `radial-gradient(circle, ${color} ${radius}px, transparent ${radius}px)`,
backgroundSize: `${spacing}px ${spacing}px`,
}"
@mousemove="handleMouseMove"
@mouseleave="handleMouseLeave"
>
<div class="dot-fade" :style="{ background: `radial-gradient(ellipse 70% 50% at 50% 50%, transparent 20%, ${bg} 100%)` }"></div>
<div
class="dot-glow"
:style="{
opacity: glowVisible ? 1 : 0,
left: glowX + 'px',
top: glowY + 'px',
}"
></div>
<div class="dot-content">
<slot>
<div class="demo-content">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#6366f1" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="opacity: 0.8">
<circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/>
<circle cx="5" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="5" r="1"/>
<circle cx="19" cy="5" r="1"/><circle cx="5" cy="19" r="1"/><circle cx="19" cy="19" r="1"/>
</svg>
<h1 class="demo-title">Dot Pattern</h1>
<p class="demo-desc">Repeating dot background using radial-gradient, fully customizable with CSS custom properties.</p>
<div class="demo-tags">
<span v-for="tag in tags" :key="tag" class="demo-tag">{{ tag }}</span>
</div>
</div>
</slot>
</div>
</div>
</template>
<style scoped>
.dot-container {
position: relative;
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
overflow: hidden;
}
.dot-fade {
position: absolute;
inset: 0;
pointer-events: none;
}
.dot-glow {
position: absolute;
width: 500px;
height: 500px;
border-radius: 50%;
background: radial-gradient(circle, rgba(99,102,241,0.08) 0%, transparent 70%);
pointer-events: none;
transform: translate(-50%, -50%);
transition: opacity 0.3s ease;
z-index: 0;
}
.dot-content {
position: relative;
z-index: 1;
}
.demo-content {
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
padding: 2rem;
}
.demo-title {
font-size: 2.5rem;
font-weight: 800;
letter-spacing: -0.03em;
line-height: 1.1;
color: #fafafa;
font-family: system-ui, -apple-system, sans-serif;
}
.demo-desc {
font-size: 1rem;
line-height: 1.7;
color: #71717a;
max-width: 380px;
font-family: system-ui, -apple-system, sans-serif;
}
.demo-tags {
display: flex;
gap: 0.5rem;
margin-top: 0.5rem;
}
.demo-tag {
font-size: 0.75rem;
font-weight: 500;
padding: 0.25rem 0.75rem;
border-radius: 999px;
background: rgba(99,102,241,0.1);
border: 1px solid rgba(99,102,241,0.2);
color: #a5b4fc;
}
</style><script>
export let spacing = 24;
export let radius = 1;
export let color = "rgba(255,255,255,0.15)";
export let bg = "#0a0a0a";
let glowX = 0;
let glowY = 0;
let glowVisible = false;
function handleMouseMove(e) {
const rect = e.currentTarget.getBoundingClientRect();
glowX = e.clientX - rect.left;
glowY = e.clientY - rect.top;
glowVisible = true;
}
function handleMouseLeave() {
glowVisible = false;
}
</script>
<div
class="dot-container"
style="
background-color: {bg};
background-image: radial-gradient(circle, {color} {radius}px, transparent {radius}px);
background-size: {spacing}px {spacing}px;
"
on:mousemove={handleMouseMove}
on:mouseleave={handleMouseLeave}
>
<div class="dot-fade" style="background: radial-gradient(ellipse 70% 50% at 50% 50%, transparent 20%, {bg} 100%);"></div>
<div
class="dot-glow"
style="
opacity: {glowVisible ? 1 : 0};
left: {glowX}px;
top: {glowY}px;
"
></div>
<div class="dot-content">
<slot>
<div class="demo-content">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#6366f1" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="opacity: 0.8">
<circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/>
<circle cx="5" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="5" r="1"/>
<circle cx="19" cy="5" r="1"/><circle cx="5" cy="19" r="1"/><circle cx="19" cy="19" r="1"/>
</svg>
<h1 class="demo-title">Dot Pattern</h1>
<p class="demo-desc">Repeating dot background using radial-gradient, fully customizable with CSS custom properties.</p>
<div class="demo-tags">
{#each ['CSS', 'radial-gradient', 'pattern'] as tag}
<span class="demo-tag">{tag}</span>
{/each}
</div>
</div>
</slot>
</div>
</div>
<style>
.dot-container {
position: relative;
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
overflow: hidden;
}
.dot-fade {
position: absolute;
inset: 0;
pointer-events: none;
}
.dot-glow {
position: absolute;
width: 500px;
height: 500px;
border-radius: 50%;
background: radial-gradient(circle, rgba(99,102,241,0.08) 0%, transparent 70%);
pointer-events: none;
transform: translate(-50%, -50%);
transition: opacity 0.3s ease;
z-index: 0;
}
.dot-content {
position: relative;
z-index: 1;
}
.demo-content {
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
padding: 2rem;
}
.demo-title {
font-size: 2.5rem;
font-weight: 800;
letter-spacing: -0.03em;
line-height: 1.1;
color: #fafafa;
font-family: system-ui, -apple-system, sans-serif;
}
.demo-desc {
font-size: 1rem;
line-height: 1.7;
color: #71717a;
max-width: 380px;
font-family: system-ui, -apple-system, sans-serif;
}
.demo-tags {
display: flex;
gap: 0.5rem;
margin-top: 0.5rem;
}
.demo-tag {
font-size: 0.75rem;
font-weight: 500;
padding: 0.25rem 0.75rem;
border-radius: 999px;
background: rgba(99,102,241,0.1);
border: 1px solid rgba(99,102,241,0.2);
color: #a5b4fc;
}
</style>Dot Pattern
A sleek repeating dot pattern background using radial-gradient, perfect for adding subtle texture to dark-themed sections.
How it works
A single radial-gradient creates a circle at the center of a repeating tile. The background-size property controls dot spacing, and the gradient stop controls dot radius. Everything is driven by CSS custom properties.
Customization
| Variable | Default | Description |
|---|---|---|
--dot-spacing | 24px | Distance between dot centers |
--dot-radius | 1px | Dot radius |
--dot-color | rgba(255,255,255,0.15) | Dot fill color |
--dot-bg | #0a0a0a | Background color |
When to use it
- Subtle section backgrounds
- Card or modal backdrops
- Empty state containers
- Behind hero typography