Skip to content

Instantly share code, notes, and snippets.

@diegohaz
Last active August 26, 2025 06:57
Show Gist options
  • Select an option

  • Save diegohaz/341ed774ebac3b4dd820ae48d8bc822c to your computer and use it in GitHub Desktop.

Select an option

Save diegohaz/341ed774ebac3b4dd820ae48d8bc822c to your computer and use it in GitHub Desktop.
Ariakit Notification API

Simple notifications

import * as Ariakit from "@ariakit/react";

function Example() {
  const notification = Ariakit.useNotificationContext();
  return (
    <>
      <button
        onClick={() => {
          notification?.push("Hello");
          notification?.push("Hello", { role: "status" });
          notification?.push("Hello", { timeout: 10000 });
          notification?.push("Hello", { visuallyHidden: true });
        }}
      >
        Push notification
      </button>
    </>
  );
}

export default function App() {
  return (
    <Ariakit.NotificationProvider>
      <Example />
      <div>
        <Ariakit.NotificationItems>
          {(items) => (
            items.map((props) => (
              <Ariakit.Notification key={props.id} {...props}>
                {props.children}
                <Ariakit.NotificationDismiss />
              </Ariakit.Notification>
            ))
          )}
        </Ariakit.NotificationItems>
      </div>
    </Ariakit.NotificationProvider>
  );
}

Custom notifications

// notifications.tsx
import * as Ariakit from "@ariakit/react";

interface Item extends Ariakit.NotificationStoreItem {
  onUndo?: () => void;
}

export function useNotification() {
  const notification = Ariakit.useNotificationContext();
  if (!notification) {
    throw new Error("Missing NotificationProvider");
  }
  return notification as Ariakit.NotificationStore<Item>;
}

export function Notifications({ children }) {
  return (
    <Ariakit.NotificationProvider>
      {children}
      <div>
        <Ariakit.NotificationItems<Item>>
          {(items) => (
            items.map(({ onUndo, ...props }) => (
              <Ariakit.Notification key={props.id} {...props}>
                {props.children}
                <Ariakit.NotificationDismiss />
                {onUndo && <button onClick={onUndo}>Undo</button>}
              </Ariakit.Notification>
            ))
          )}
        </Ariakit.NotificationItems>
      </div>
    </Ariakit.NotificationProvider>
  );
}
// index.tsx
import { Notifications, useNotification } from "./notifications.tsx";

function Example() {
  const { push } = useNotification();
  return (
    <>
      <button
        onClick={() => {
          push("Hello");
          push("Hello", { role: "status" });
          push("Hello", { onUndo: () => {}, timeout: 10000 });
          push("Hello", { visuallyHidden: true });
        }}
      >
        Push notification
      </button>
    </>
  );
}

export default function App() {
  return (
    <Notifications>
      <Example />
    </Notifications>
  );
}
@diegohaz
Copy link
Author

diegohaz commented Oct 22, 2024

Comment by @alvarlagerlof for future reference:

How does your notification store handle multiple SSR renders on a single server? Does it leak state considering it's module scoped?

https://x.com/alvarlagerlof/status/1848740406365753802

This could become an issue if someone needs to render an initial notification on the server. They might have to instantiate the store within the component, which would prevent them from exporting push, or they might need to mutate the store on the server, potentially affecting other clients (this needs testing).

Edit: Updated the code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment