Saltar al contenido
ssntl/ui

Empty state

Una pantalla vacía que dice qué aparecerá aquí y ofrece la acción que la llena.

No projects yet

Projects you create appear here, with their status and next delivery.

Instalación

$ pnpm dlx shadcn@latest add @ssntl/empty-state

Uso

tsx
import { EmptyState, EmptyStateActions, EmptyStateDescription, EmptyStateIcon, EmptyStateTitle } from "@/components/ui/empty-state"

<EmptyState>
  <EmptyStateIcon><FolderPlus /></EmptyStateIcon>
  <EmptyStateTitle>Aún no hay proyectos</EmptyStateTitle>
  <EmptyStateDescription>Los proyectos que crees aparecen aquí.</EmptyStateDescription>
  <EmptyStateActions><Button>Crear proyecto</Button></EmptyStateActions>
</EmptyState>
  • Di qué aparecerá aquí y por qué está vacío; nunca solo “Sin datos”.
  • Ofrece la única acción que lo llena, como botón primary.
  • El ícono es decorativo (aria-hidden); el título lleva el significado.

Código

components/ui/empty-state.tsx
import * as React from "react"

import { cn } from "@/lib/utils"

// An empty screen invites the next action: say what will appear here, why it
// is empty, and offer the one action that fills it. Never just "No data".
function EmptyState({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="empty-state"
      className={cn(
        "flex min-w-0 flex-col items-center gap-2 rounded-lg bg-muted px-6 py-12 text-center",
        className
      )}
      {...props}
    />
  )
}

function EmptyStateIcon({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      aria-hidden
      data-slot="empty-state-icon"
      className={cn(
        "mb-2 grid size-11 place-items-center rounded-full bg-secondary text-foreground [&_svg]:size-5",
        className
      )}
      {...props}
    />
  )
}

function EmptyStateTitle({ className, ...props }: React.ComponentProps<"h3">) {
  return (
    <h3
      data-slot="empty-state-title"
      className={cn("text-heading", className)}
      {...props}
    />
  )
}

function EmptyStateDescription({
  className,
  ...props
}: React.ComponentProps<"p">) {
  return (
    <p
      data-slot="empty-state-description"
      className={cn(
        "max-w-sm text-body text-balance text-muted-foreground",
        className
      )}
      {...props}
    />
  )
}

function EmptyStateActions({
  className,
  ...props
}: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="empty-state-actions"
      className={cn("mt-4 flex flex-wrap justify-center gap-2", className)}
      {...props}
    />
  )
}

export {
  EmptyState,
  EmptyStateActions,
  EmptyStateDescription,
  EmptyStateIcon,
  EmptyStateTitle,
}