Use the Empty component to display an empty state.
Installation
npx shadcn@latest add @caprice/emptynpm install @caprice-ui/reactInstall the following dependencies:
npm install @base-ui/react lucide-reactAdd a cn helper
import { defineConfig, type VariantProps } from 'cva';import { twMerge } from 'tailwind-merge';export const { compose, cva, cx: cn,} = defineConfig({ hooks: { onComplete: (className: string) => twMerge(className), },});export type { VariantProps };Copy and paste the following code into your project.
import { mergePropsN, useRender } from '@base-ui/react';import { cn, cva, type VariantProps } from '@/lib/utils';/** * Groups all parts of the empty state. * Renders a `<div>` element. * * Documentation: [Caprice UI Empty](https://caprice-ui.com/docs/components/empty) */export namespace Root { export type Props = useRender.ComponentProps<'div'>;}export function Root({ className, render, ...props }: Root.Props) { const defaultProps: useRender.ElementProps<'div'> & { 'data-slot'?: string } = { 'data-slot': 'empty', className: cn( 'flex min-w-0 flex-1 flex-col items-center justify-center gap-6 text-balance rounded-lg border-dashed p-6 text-center md:p-12', className ), }; return useRender({ defaultTagName: 'div', render, props: mergePropsN<'div'>([defaultProps, props]), });}/** * A container for the empty state media, title, and description. * Renders a `<div>` element. * * Documentation: [Caprice UI Empty](https://caprice-ui.com/docs/components/empty) */export namespace Header { export type Props = useRender.ComponentProps<'div'>;}export function Header({ className, render, ...props }: Header.Props) { const defaultProps: useRender.ElementProps<'div'> & { 'data-slot'?: string } = { 'data-slot': 'empty-header', className: cn('flex max-w-sm flex-col items-center gap-2 text-center', className), }; return useRender({ defaultTagName: 'div', render, props: mergePropsN<'div'>([defaultProps, props]), });}const emptyMediaVariants = cva({ base: 'mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0', variants: { variant: { default: 'bg-transparent', icon: "flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg:not([class*='size-'])]:size-6", }, }, defaultVariants: { variant: 'default', },});export namespace Media { export type Variants = VariantProps<typeof emptyMediaVariants>; export type Props = useRender.ComponentProps<'div'> & Media.Variants;}/** * A visual representation of the empty state. * Renders a `<div>` element. * * Documentation: [Caprice UI Empty](https://caprice-ui.com/docs/components/empty) */export function Media({ className, variant = 'default', render, ...props }: Media.Props) { const defaultProps: useRender.ElementProps<'div'> & { 'data-slot'?: string } = { 'data-slot': 'empty-icon', className: cn(emptyMediaVariants({ variant, className })), }; return useRender({ defaultTagName: 'div', render, props: mergePropsN<'div'>([defaultProps, props]), });}/** * The title of the empty state. * Renders a `<div>` element. * * Documentation: [Caprice UI Empty](https://caprice-ui.com/docs/components/empty) */export namespace Title { export type Props = useRender.ComponentProps<'div'>;}export function Title({ className, render, ...props }: Title.Props) { const defaultProps: useRender.ElementProps<'div'> & { 'data-slot'?: string } = { 'data-slot': 'empty-title', className: cn('font-medium text-lg tracking-tight', className), }; return useRender({ defaultTagName: 'div', render, props: mergePropsN<'div'>([defaultProps, props]), });}/** * The description of the empty state. * Renders a `<p>` element. * * Documentation: [Caprice UI Empty](https://caprice-ui.com/docs/components/empty) */export namespace Description { export type Props = useRender.ComponentProps<'p'>;}export function Description({ className, render, ...props }: Description.Props) { const defaultProps: useRender.ElementProps<'p'> & { 'data-slot'?: string } = { 'data-slot': 'empty-description', className: cn( 'text-muted-foreground text-sm/relaxed [&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4', className ), }; return useRender({ defaultTagName: 'p', render, props: mergePropsN<'p'>([defaultProps, props]), });}/** * A container for the empty state content. * Renders a `<div>` element. * * Documentation: [Caprice UI Empty](https://caprice-ui.com/docs/components/empty) */export namespace Content { export type Props = useRender.ComponentProps<'div'>;}export function Content({ className, render, ...props }: Content.Props) { const defaultProps: useRender.ElementProps<'div'> & { 'data-slot'?: string } = { 'data-slot': 'empty-content', className: cn( 'flex w-full min-w-0 max-w-sm flex-col items-center gap-4 text-balance text-sm', className ), }; return useRender({ defaultTagName: 'div', render, props: mergePropsN<'div'>([defaultProps, props]), });}Update the import paths to match your project setup.
Usage
import * as Empty from "@/components/caprice-ui/empty"import * as Empty from "@caprice-ui/react/empty"