Particular.Tech
Feedbackui

Banner

Full-width announcement or incident bar, optionally dismissible.

Branching for object storage is now generally available.Read the changelog
Elevated build times in eu-central-1.
Scheduled maintenance on Sunday, 02:00–03:00 UTC.

Installation

npx shadcn@latest add @particular/banner
npm dependencies
  • class-variance-authority@^0.7.1
  • cn@^0.4.0
  • lucide-react@^1.51.0
Installs these registry items

Source

ui/banner.tsx
"use client"

import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { XIcon } from "lucide-react"
import { cn } from "cn"

import { Button } from "@/components/ui/button"

const bannerVariants = cva(
  "relative flex w-full items-center justify-center gap-3 px-10 py-2 text-center text-sm [&>svg]:size-4 [&>svg]:shrink-0",
  {
    variants: {
      tone: {
        neutral: "bg-muted text-foreground",
        brand: "bg-brand text-brand-foreground",
        info: "bg-info-subtle text-info",
        success: "bg-success-subtle text-success",
        warning: "bg-warning-subtle text-warning",
        destructive: "bg-destructive text-destructive-foreground",
      },
    },
    defaultVariants: { tone: "neutral" },
  }
)

function Banner({
  tone,
  dismissible = false,
  onDismiss,
  action,
  className,
  children,
  ...props
}: React.ComponentProps<"div"> &
  VariantProps<typeof bannerVariants> & {
    dismissible?: boolean
    onDismiss?: () => void
    action?: React.ReactNode
  }) {
  const [dismissed, setDismissed] = React.useState(false)
  if (dismissed) return null

  return (
    <div data-slot="banner" role="region" aria-label="Announcement" className={cn(bannerVariants({ tone }), className)} {...props}>
      {children}
      {action}
      {dismissible && (
        <Button
          variant="ghost"
          size="icon-xs"
          aria-label="Dismiss"
          className="absolute right-2 text-current hover:bg-current/10 hover:text-current"
          onClick={() => {
            setDismissed(true)
            onDismiss?.()
          }}
        >
          <XIcon />
        </Button>
      )}
    </div>
  )
}

export { Banner, bannerVariants }