Meet Frontfriend.Your brand. Your rules. Your agents, connected.Explore what’s new

Empty

Use the Empty component to display an empty state.

Interactive preview

Rendered from the shared Frontfriend stories with React Base, the same preview Studio shows. Styling comes from your Design System; the code below is native to React Aria.

Installation

Complete project setup first. Your configuration must select react/aria and include your Design System ID.

pnpm exec frontfriend download empty -f react --primitive aria

Review dependencies reported by the downloader and keep your source changes in version control.

Usage

import {
  Empty,
  EmptyHeader,
  EmptyMedia,
  EmptyTitle,
  EmptyDescription,
} from "@/components/ui/empty";
import { Icon } from "@/components/ui/icon";
<Empty className="w-96 border">
  <EmptyHeader>
    <EmptyMedia variant="icon">
      <Icon name="Folder" />
    </EmptyMedia>
    <EmptyTitle>No projects yet</EmptyTitle>
    <EmptyDescription>Create your first project.</EmptyDescription>
  </EmptyHeader>
</Empty>;

Examples

Default

import {
  Empty,
  EmptyHeader,
  EmptyMedia,
  EmptyTitle,
  EmptyDescription,
  EmptyContent,
} from "@/components/ui/empty";
import { FolderCodeIcon, ArrowUpRightIcon } from "lucide-react";
import { Button, LinkButton } from "@/components/ui/button";
<Empty >
  <EmptyHeader>
    <EmptyMedia variant="icon">
      <FolderCodeIcon />
    </EmptyMedia>
    <EmptyTitle>No Projects Yet</EmptyTitle>
    <EmptyDescription>
      You haven't created any projects yet. Get started by creating your first
      project.
    </EmptyDescription>
  </EmptyHeader>
  <EmptyContent className="flex-row justify-center gap-2">
    <Button>Create Project</Button>
    <Button variant="tertiary">Import Project</Button>
  </EmptyContent>
  <LinkButton href="#" variant="link" className="text-neutral-mid" size="sm">
    Learn More <ArrowUpRightIcon />
  </LinkButton>
</Empty>;

Outline

import {
  Empty,
  EmptyHeader,
  EmptyMedia,
  EmptyTitle,
  EmptyDescription,
  EmptyContent,
} from "@/components/ui/empty";
import { CloudIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
<Empty className="border border-dashed">
  <EmptyHeader>
    <EmptyMedia variant="icon">
      <CloudIcon />
    </EmptyMedia>
    <EmptyTitle>Cloud Storage Empty</EmptyTitle>
    <EmptyDescription>
      Upload files to your cloud storage to access them anywhere.
    </EmptyDescription>
  </EmptyHeader>
  <EmptyContent>
    <Button variant="tertiary" size="sm">
      Upload Files
    </Button>
  </EmptyContent>
</Empty>;

Background

import {
  Empty,
  EmptyHeader,
  EmptyMedia,
  EmptyTitle,
  EmptyDescription,
  EmptyContent,
} from "@/components/ui/empty";
import { BellIcon, RefreshCcwIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
<Empty className="bg-neutral-subtle/30">
  <EmptyHeader>
    <EmptyMedia variant="icon">
      <BellIcon />
    </EmptyMedia>
    <EmptyTitle>No Notifications</EmptyTitle>
    <EmptyDescription className="max-w-xs text-pretty">
      You're all caught up. New notifications will appear here.
    </EmptyDescription>
  </EmptyHeader>
  <EmptyContent>
    <Button variant="tertiary">
      <RefreshCcwIcon />
      Refresh
    </Button>
  </EmptyContent>
</Empty>;

Avatar

import {
  Empty,
  EmptyHeader,
  EmptyMedia,
  EmptyTitle,
  EmptyDescription,
  EmptyContent,
} from "@/components/ui/empty";
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
<Empty>
  <EmptyHeader>
    <EmptyMedia variant="default">
      <Avatar className="size-12">
        <AvatarImage
          src="https://github.com/shadcn.png"
          className="grayscale"
        />
        <AvatarFallback>LR</AvatarFallback>
      </Avatar>
    </EmptyMedia>
    <EmptyTitle>User Offline</EmptyTitle>
    <EmptyDescription>
      This user is currently offline. You can leave a message to notify them or
      try again later.
    </EmptyDescription>
  </EmptyHeader>
  <EmptyContent>
    <Button size="sm">Leave Message</Button>
  </EmptyContent>
</Empty>;

With Input Group

import {
  Empty,
  EmptyHeader,
  EmptyTitle,
  EmptyDescription,
  EmptyContent,
} from "@/components/ui/empty";
import {
  InputGroup,
  InputGroupInput,
  InputGroupAddon,
} from "@/components/ui/input-group";
import { SearchIcon } from "lucide-react";
import { Kbd } from "@/components/ui/kbd";
<Empty>
  <EmptyHeader>
    <EmptyTitle>404 - Not Found</EmptyTitle>
    <EmptyDescription>
      The page you're looking for doesn't exist. Try searching for what you need
      below.
    </EmptyDescription>
  </EmptyHeader>
  <EmptyContent>
    <InputGroup className="sm:w-3/4">
      <InputGroupInput placeholder="Try searching for pages..." />
      <InputGroupAddon>
        <SearchIcon />
      </InputGroupAddon>
      <InputGroupAddon align="inline-end">
        <Kbd>/</Kbd>
      </InputGroupAddon>
    </InputGroup>
    <EmptyDescription>
      Need help? <a href="#">Contact support</a>
    </EmptyDescription>
  </EmptyContent>
</Empty>;

API reference

Frontfriend-owned props. Native HTML and inherited primitive props remain documented by React Aria.

Prop Type Default Description
variant "default" | "icon" "default"

Configuration determines the actual classes and available styling hooks. See Theming & component configuration before introducing a repeated local override.