# Announcement banner

> The newest live announcement for the user and organization, with a dismiss button.

Source: https://bettersupabase.com/docs/registry/ui-recipes/announcement-banner

{/* Generated by scripts/build-recipes.ts from the example apps. Edit the examples or the script, then run `pnpm recipes`. */}

It calls `useAnnouncements` from `better-supabase/blocks/announcements/react`; the [announcements block](https://bettersupabase.com/blocks/announcements) must be installed (`npx better-supabase add announcements`). Its page on bettersupabase.com is [/recipes/announcement-banner](https://bettersupabase.com/recipes/announcement-banner).

Web, with shadcn components:

```bash
npx shadcn add alert button
```

```tsx title="apps/examples/nextjs/src/features/announcements/components/announcement-banner.tsx"
"use client";

import { useAnnouncements } from "better-supabase/blocks/announcements/react";
import { MegaphoneIcon, XIcon } from "lucide-react";
import { useExtracted } from "next-intl";

import {
  Alert,
  AlertAction,
  AlertDescription,
  AlertTitle,
} from "@/components/ui/alert";
import { Button } from "@/components/ui/button";

/**
 * The newest live announcement for this user and organization. Loads in the
 * browser and reloads on the module's broadcast, so it adds nothing to the
 * server render.
 */
export function AnnouncementBanner({
  organizationId,
}: {
  organizationId: string | null;
}) {
  const t = useExtracted("announcements");

  const { items, dismiss } = useAnnouncements({
    organizationId,
    schema: "api",
  });

  const announcement = items?.[0];

  if (!announcement) {
    return null;
  }

  return (
    <Alert
      variant={announcement.severity === "critical" ? "destructive" : "default"}
      data-testid="announcement"
    >
      <MegaphoneIcon />
      <AlertTitle>{announcement.title}</AlertTitle>
      {announcement.body ? (
        <AlertDescription>{announcement.body}</AlertDescription>
      ) : null}
      {announcement.dismissible ? (
        <AlertAction>
          <Button
            variant="ghost"
            size="icon-sm"
            aria-label={t("Dismiss")}
            onClick={() => void dismiss(announcement.id)}
          >
            <XIcon />
          </Button>
        </AlertAction>
      ) : null}
    </Alert>
  );
}
```