diff --git a/components/docs/interactive-examples/dot-background.tsx b/components/docs/interactive-examples/dot-background.tsx
new file mode 100644
index 0000000..8d328d7
--- /dev/null
+++ b/components/docs/interactive-examples/dot-background.tsx
@@ -0,0 +1,121 @@
+import { DotBackground } from "@/registry/radix-nova/dot-background"
+
+const colorVariants = [
+ {
+ variant: "default",
+ label: "Default",
+ description: "Uses the default surface and border tokens.",
+ },
+ {
+ variant: "muted",
+ label: "Muted",
+ description: "A softer surface for secondary sections.",
+ },
+ {
+ variant: "card",
+ label: "Card",
+ description: "Blends into card-based layouts.",
+ },
+ {
+ variant: "accent",
+ label: "Accent",
+ description: "Adds stronger contrast for callouts.",
+ },
+ {
+ variant: "secondary",
+ label: "Secondary",
+ description: "Works well inside layered UIs.",
+ },
+] as const
+
+const spacingVariants = [
+ {
+ spacing: "dense",
+ label: "Dense",
+ description: "Tighter pattern for more texture.",
+ },
+ {
+ spacing: "default",
+ label: "Default",
+ description: "Balanced density for general use.",
+ },
+ {
+ spacing: "relaxed",
+ label: "Relaxed",
+ description: "Airier spacing for larger panels.",
+ },
+ {
+ spacing: "loose",
+ label: "Loose",
+ description: "Sparse dots for subtle decoration.",
+ },
+] as const
+
+export function DotBackgroundInteractiveExample() {
+ return (
+
+
+ {colorVariants.map(({ variant, label, description }) => (
+
+
+
+
{label}
+
{description}
+
+
{`variant="${variant}"`}
+
+
+ ))}
+
+
+
+ {spacingVariants.map(({ spacing, label, description }) => (
+
+
+
+
{label}
+
{description}
+
+
{`spacing="${spacing}"`}
+
+
+ ))}
+
+
+
+
+
+
Custom
+
+ Override surface color, dot color, spacing, and dot size with
+ `vars`.
+
+
+
+ {`variant="custom" spacing="custom"`}
+
+
+
+
+ )
+}
diff --git a/components/docs/interactive-examples/index.ts b/components/docs/interactive-examples/index.ts
index a1e873e..96f76f3 100644
--- a/components/docs/interactive-examples/index.ts
+++ b/components/docs/interactive-examples/index.ts
@@ -2,5 +2,6 @@ export { AlertDialogInteractiveExample } from "./alert-dialog"
export { ButtonInteractiveExample } from "./button"
export { ConfirmDialogInteractiveExample } from "./confirm-dialog"
export { DialogInteractiveExample } from "./dialog"
+export { DotBackgroundInteractiveExample } from "./dot-background"
export { FilepickerDropzoneInteractiveExample } from "./filepicker-dropzone"
export { LoadingButtonInteractiveExample } from "./loading-button"
diff --git a/content/docs/components/dot-background.mdx b/content/docs/components/dot-background.mdx
new file mode 100644
index 0000000..86eabfa
--- /dev/null
+++ b/content/docs/components/dot-background.mdx
@@ -0,0 +1,103 @@
+---
+title: Dot Background
+description: A dotted surface wrapper with semantic color and spacing variants plus CSS variable overrides.
+---
+
+import { DotBackgroundInteractiveExample } from "@/components/docs/interactive-examples";
+
+## Install
+
+```bash
+npx shadcn@latest add @c-ui/dot-background
+```
+
+Direct URL install:
+
+```bash
+npx shadcn@latest add https://coneno.github.io/c-ui/r/radix-nova/dot-background.json
+```
+
+## Live Example
+
+
+
+
+
+## Usage
+
+```tsx
+import { DotBackground } from "@/components/ui/dot-background"
+
+export function HeroSurface() {
+ return (
+
+
+
Patterned container
+
+ Add subtle texture without leaving your design tokens.
+
+
+
+ )
+}
+```
+
+## Color Variants
+
+```tsx
+
+
+
+
+
+```
+
+## Spacing Variants
+
+```tsx
+
+
+
+
+```
+
+## Custom Overrides
+
+Use `variant="custom"` and `spacing="custom"` when you want the surface to be driven entirely by `vars`.
+
+```tsx
+
+
+
Custom surface
+
+ Tune the density and dot size with numbers or raw CSS lengths.
+
+
+
+```
+
+## Configuration
+
+| Prop | Type | Default | Notes |
+| --- | --- | --- | --- |
+| `variant` | `"default" \| "muted" \| "card" \| "accent" \| "secondary" \| "custom"` | `"default"` | Semantic background palette |
+| `spacing` | `"dense" \| "default" \| "relaxed" \| "loose" \| "custom"` | `"default"` | Controls the dot grid spacing |
+| `vars.backgroundColor` | `string` | `undefined` | Overrides the surface color |
+| `vars.dotColor` | `string` | `undefined` | Overrides the dot color |
+| `vars.spacing` | `number \| string` | `undefined` | Custom dot spacing; numbers become `px` |
+| `vars.dotSize` | `number \| string` | `undefined` | Custom dot size; numbers become `px` |
+| `asChild` | `boolean` | `false` | Render the pattern styles onto a child element via Radix `Slot` |
+| `className` | `string` | `undefined` | Extends layout and border styling |
+| `style` | `React.CSSProperties` | `undefined` | Supports the `--dot-background-*` CSS custom properties directly |
+
+All native `` props are forwarded.
diff --git a/registry.json b/registry.json
index edf4ea6..0735a02 100644
--- a/registry.json
+++ b/registry.json
@@ -75,6 +75,20 @@
],
"style": "radix-nova"
},
+ {
+ "name": "dot-background",
+ "type": "registry:component",
+ "title": "Dot Background",
+ "description": "A dotted surface wrapper with semantic color and spacing variants.",
+ "files": [
+ {
+ "path": "registry/radix-nova/dot-background.tsx",
+ "type": "registry:component",
+ "target": "components/ui/dot-background.tsx"
+ }
+ ],
+ "style": "radix-nova"
+ },
{
"name": "loading-button",
"type": "registry:component",
diff --git a/registry/radix-nova/dot-background.tsx b/registry/radix-nova/dot-background.tsx
new file mode 100644
index 0000000..c99060b
--- /dev/null
+++ b/registry/radix-nova/dot-background.tsx
@@ -0,0 +1,161 @@
+import * as React from "react"
+import { cva } from "class-variance-authority"
+import { Slot } from "radix-ui"
+
+import { cn } from "@/lib/utils"
+
+const dotBackgroundColorVariants = {
+ default: {
+ backgroundColor: "var(--background)",
+ dotColor: "var(--border)",
+ },
+ muted: {
+ backgroundColor: "var(--muted)",
+ dotColor: "color-mix(in oklab, var(--muted-foreground) 24%, transparent)",
+ },
+ card: {
+ backgroundColor: "var(--card)",
+ dotColor: "color-mix(in oklab, var(--border) 90%, transparent)",
+ },
+ accent: {
+ backgroundColor: "var(--accent)",
+ dotColor: "color-mix(in oklab, var(--accent-foreground) 18%, transparent)",
+ },
+ secondary: {
+ backgroundColor: "var(--secondary)",
+ dotColor:
+ "color-mix(in oklab, var(--secondary-foreground) 16%, transparent)",
+ },
+ custom: {
+ backgroundColor: "var(--background)",
+ dotColor: "var(--border)",
+ },
+} as const satisfies Record<
+ string,
+ { backgroundColor: string; dotColor: string }
+>
+
+const dotBackgroundSpacingVariants = {
+ dense: { spacing: "0.875rem" },
+ default: { spacing: "1.25rem" },
+ relaxed: { spacing: "1.75rem" },
+ loose: { spacing: "2.25rem" },
+ custom: { spacing: "1.25rem" },
+} as const satisfies Record
+
+type DotBackgroundVariant = keyof typeof dotBackgroundColorVariants
+type DotBackgroundSpacingVariant = keyof typeof dotBackgroundSpacingVariants
+
+const defaultDotBackgroundVariant: DotBackgroundVariant = "default"
+const defaultDotBackgroundSpacing: DotBackgroundSpacingVariant = "default"
+const defaultDotBackgroundDotSize = "1px"
+
+function createVariantEntries>(variants: T) {
+ return Object.fromEntries(
+ Object.keys(variants).map((key) => [key, ""])
+ ) as Record
+}
+
+const dotBackgroundVariants = cva("relative isolate", {
+ variants: {
+ variant: createVariantEntries(dotBackgroundColorVariants),
+ spacing: createVariantEntries(dotBackgroundSpacingVariants),
+ },
+ defaultVariants: {
+ variant: defaultDotBackgroundVariant,
+ spacing: defaultDotBackgroundSpacing,
+ },
+})
+
+type DotBackgroundStyle = React.CSSProperties & {
+ "--dot-background-color"?: string
+ "--dot-background-dot-color"?: string
+ "--dot-background-spacing"?: string
+ "--dot-background-dot-size"?: string
+}
+
+type DotBackgroundResolvedStyle = DotBackgroundStyle & {
+ "--dot-pattern-bg"?: string
+ "--dot-pattern-color"?: string
+ "--dot-pattern-spacing"?: string
+ "--dot-pattern-dot-size"?: string
+}
+
+type DotBackgroundVars = {
+ backgroundColor?: string
+ dotColor?: string
+ spacing?: number | string
+ dotSize?: number | string
+}
+
+type DotBackgroundProps = Omit, "style"> & {
+ asChild?: boolean
+ variant?: DotBackgroundVariant
+ spacing?: DotBackgroundSpacingVariant
+ vars?: DotBackgroundVars
+ style?: DotBackgroundStyle
+}
+
+function resolveCssLength(value: number | string | undefined) {
+ if (typeof value === "number") {
+ return `${value}px`
+ }
+
+ return value
+}
+
+function DotBackground({
+ asChild = false,
+ variant = defaultDotBackgroundVariant,
+ spacing = defaultDotBackgroundSpacing,
+ vars,
+ className,
+ style,
+ ...props
+}: DotBackgroundProps) {
+ const Comp = asChild ? Slot.Root : "div"
+ const colorVariant = dotBackgroundColorVariants[variant]
+ const spacingVariant = dotBackgroundSpacingVariants[spacing]
+
+ const resolvedStyle: DotBackgroundResolvedStyle = {
+ "--dot-background-color": vars?.backgroundColor,
+ "--dot-background-dot-color": vars?.dotColor,
+ "--dot-background-spacing": resolveCssLength(vars?.spacing),
+ "--dot-background-dot-size": resolveCssLength(vars?.dotSize),
+ "--dot-pattern-bg": `var(--dot-background-color, ${colorVariant.backgroundColor})`,
+ "--dot-pattern-color": `var(--dot-background-dot-color, ${colorVariant.dotColor})`,
+ "--dot-pattern-spacing": `var(--dot-background-spacing, ${spacingVariant.spacing})`,
+ "--dot-pattern-dot-size": `var(--dot-background-dot-size, ${defaultDotBackgroundDotSize})`,
+ backgroundColor: "var(--dot-pattern-bg)",
+ backgroundImage:
+ "radial-gradient(circle, var(--dot-pattern-color) var(--dot-pattern-dot-size), transparent calc(var(--dot-pattern-dot-size) + 0.5px))",
+ backgroundSize: "var(--dot-pattern-spacing) var(--dot-pattern-spacing)",
+ backgroundPosition: "0 0",
+ ...style,
+ }
+
+ return (
+
+ )
+}
+
+export {
+ DotBackground,
+ dotBackgroundColorVariants,
+ dotBackgroundSpacingVariants,
+ dotBackgroundVariants,
+}
+export type {
+ DotBackgroundProps,
+ DotBackgroundSpacingVariant,
+ DotBackgroundStyle,
+ DotBackgroundVariant,
+ DotBackgroundVars,
+}