Skip to content
    Style: Wireframe

    Components · Feedback

    Empty state

    Nothing here yet, or no results: a mark, what is going on, what to do, announced when it replaces results.

    0.77% of the 2,073 sites in The UI Index have a empty state (16 sites).

    No projects yet

    Connect a repository and your first deploy starts right away.

    No deploys match “pricng”

    Check the spelling, or clear the filters.

    Both previews render the same markup; the HTML tab below is that markup without a framework.

    Install

    React
    npx shadcn@latest add https://www.themes.dev/ui/r/empty-state.json
    Astro
    npx shadcn@latest add https://www.themes.dev/ui/r/astro/empty-state.json

    Or copy the files below into your project. They need clsx, tailwind-merge, and the themes.dev UI theme. The HTML needs only the compiled CSS.

    empty-state.tsx
    import type { ReactNode } from 'react';
    import { cn } from '@/lib/utils';
    import { emptyState, MARKS } from './empty-state.variants';
    
    export interface EmptyStateProps {
      title: string;
      description?: string;
      mark?: keyof typeof MARKS;
      /** It replaces results (a search, a filter): announce it. */
      live?: boolean;
      /** One or two actions. */
      children?: ReactNode;
      className?: string;
    }
    
    /** Nothing here yet, or no results: a mark, what is going on, what to do. */
    export function EmptyState({ title, description, mark = 'inbox', live, children, className }: EmptyStateProps) {
      return (
        <div role={live ? 'status' : undefined} className={cn(emptyState.root, className)}>
          <span className={emptyState.mark} aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d={MARKS[mark]} /></svg></span>
          <p className={emptyState.title}>{title}</p>
          {description && <p className={emptyState.description}>{description}</p>}
          {children && <div className={emptyState.actions}>{children}</div>}
        </div>
      );
    }
    empty-state.variants.ts
    /** An empty state: nothing here yet, or no results. A small drawn mark, one line on what is going on, one on what to
     *  do, and at most two actions. Centred on its own (it is the whole content of its area); role=status when it
     *  replaces results, so the change is announced. */
    export const emptyState = {
      // h-full: side by side, the actions of a row line up at the bottom.
      root: 'mx-auto flex h-full w-full max-w-sm flex-col items-center px-6 py-10 text-center',
      mark: 'grid size-12 place-items-center rounded-full bg-muted text-muted-foreground [&_svg]:size-5',
      title: 'mt-4 text-base font-semibold text-balance',
      description: 'mt-1.5 text-sm text-pretty text-muted-foreground',
      actions: 'mt-auto flex flex-wrap justify-center gap-2 pt-5',
    };
    export const MARKS = {
      search: 'M7 12.5a5.5 5.5 0 1 0 0-11 5.5 5.5 0 0 0 0 11zM11 11l3.5 3.5',
      inbox: 'M2 9h3.5l1 2h3l1-2H14M2 9l1.5-5.5h9L14 9v3.5H2z',
      plus: 'M8 3v10M3 8h10',
    };