Primitives
Empty
BetaBeta — the props contract is close to final, but small breaking changes can still land.Empty-state layout for blank lists, zero results, and new workspaces.
Composition
Anatomy
- <Empty>
- <EmptyHeader>
- <EmptyMedia />
- <EmptyTitle />
- <EmptyDescription />
- <EmptyContent>
- <Button />
- <EmptyHeader>
Installation
First install and activate one skin. Core deliberately contains no visual token defaults.
The Control UI source installs this primitive from src/registry/sources/control-ui/ui/empty.tsx.
npx shadcn@latest add https://control-ui.dev/r/empty.jsonRaw code
Primary installed source
"use client";import { useRender } from "@base-ui/react/use-render";import type { ComponentProps, CSSProperties } from "react";import type { RenderProp } from "@/components/control-ui/control-props";import type { EmptyKnobStyle } from "@/components/control-ui/knob-contracts/empty-knobs";import { cn } from "@/components/control-ui/lib/cn";export type EmptyProps = Omit<ComponentProps<"div">, "style"> & { style?: CSSProperties & EmptyKnobStyle };export type EmptyHeaderProps = Omit<ComponentProps<"div">, "style"> & { style?: CSSProperties & EmptyKnobStyle };export type EmptyMediaProps = Omit<ComponentProps<"div">, "style"> & { style?: CSSProperties & EmptyKnobStyle };export type EmptyContentProps = Omit<ComponentProps<"div">, "style"> & { style?: CSSProperties & EmptyKnobStyle };export type EmptyDescriptionProps = Omit<ComponentProps<"p">, "style"> & { style?: CSSProperties & EmptyKnobStyle };export type EmptyTitleProps = Omit<ComponentProps<"div">, "style"> & { render?: RenderProp<ComponentProps<"div">>; style?: CSSProperties & EmptyKnobStyle;};export function Empty({ className, ...props }: EmptyProps) { return ( <div data-control-ui="empty" data-control-family="empty" data-slot="root" className={cn("flex min-w-0 flex-1 flex-col items-center justify-center", className)} {...props} /> );}export function EmptyHeader({ className, ...props }: EmptyHeaderProps) { return ( <div data-control-ui="empty" data-control-family="empty" data-slot="header" className={cn("flex min-w-0 flex-col items-center", className)} {...props} /> );}export function EmptyMedia({ className, ...props }: EmptyMediaProps) { return ( <div data-control-ui="empty" data-control-family="empty" data-slot="media" className={cn("flex shrink-0 items-center justify-center [&>svg]:shrink-0", className)} {...props} /> );}export function EmptyTitle({ render, ...props }: EmptyTitleProps) { return useRender({ defaultTagName: "div", render, props: { ...props, "data-control-ui": "empty", "data-control-family": "empty", "data-slot": "title" }, });}export function EmptyDescription({ className, ...props }: EmptyDescriptionProps) { return <p data-control-ui="empty" data-control-family="empty" data-slot="description" className={className} {...props} />;}export function EmptyContent({ className, ...props }: EmptyContentProps) { return ( <div data-control-ui="empty" data-control-family="empty" data-slot="content" className={cn("flex w-full min-w-0 flex-col items-center justify-center", className)} {...props} /> );}Knobs
Typed custom properties the recipe paints with. Set one on the root — style, a utility class, or a skin — and every slot inherits it.
--cui-empty-* · 21 knobsHow the cascade resolves--cui-empty-radius<length-percentage>var(--radius-lg)--cui-empty-background<color>transparent--cui-empty-border-color<color>transparent--cui-empty-border-width<length>var(--control-rim-width)--cui-empty-border-style*solid--cui-empty-media-radius<length-percentage>var(--radius-lg)--cui-empty-media-background<color>var(--muted)--cui-empty-shadow*none--cui-empty-foreground<color>var(--foreground)--cui-empty-description-foreground<color>var(--muted-foreground)--cui-empty-media-foreground<color>var(--muted-foreground)--cui-empty-padding<length-percentage>calc(var(--spacing) * 6)--cui-empty-gap<length-percentage>calc(var(--spacing) * 6)--cui-empty-header-gap<length-percentage>calc(var(--spacing) * 2)--cui-empty-content-gap<length-percentage>calc(var(--spacing) * 2)--cui-empty-content-size<length-percentage>24rem--cui-empty-media-size<length-percentage>calc(var(--spacing) * 10)--cui-empty-media-icon-size<length-percentage>calc(var(--spacing) * 5)--cui-empty-font-size<length-percentage>var(--text-body)--cui-empty-title-font-weight<number>var(--font-weight-medium)--cui-empty-media-background-image*none