Skip to content
All Taste components

Onboarding

Allow notifications

The permission step before the system prompt: a bell with an unread badge, why it helps, and allow or not now.

tinted tile illustration · centred text · step dots · allow + not now

Stay in the loop

Get a nudge when your order ships, arrives or needs your attention.

// Mobile-first screen for a React web app; the same markup maps to React Native via NativeWind (View, Text, Pressable, react-native-svg).
import { cn } from "@/lib/utils";

function Illustration({ className }: { className?: string }) {
  return (
    <svg viewBox="0 0 220 200" aria-hidden="true" className={cn("h-full w-full", className)}>
      <path d="M50 72a70 70 0 0 0 0 60M32 60a92 92 0 0 0 0 84M170 72a70 70 0 0 1 0 60M188 60a92 92 0 0 1 0 84" strokeWidth="5" strokeLinecap="round" strokeLinejoin="round" fill="none" className="stroke-brand-400" />
      <circle cx="110" cy="42" r="8" className="fill-brand-600" />
      <path d="M110 46c-28 0-42 22-42 48v26l-12 16h108l-12-16V94c0-26-14-48-42-48z" className="fill-brand-400" />
      <path d="M86 100c0-14 6-24 16-28" strokeWidth="5" strokeLinecap="round" strokeLinejoin="round" fill="none" className="stroke-brand-200" />
      <rect x="52" y="132" width="116" height="11" rx="5.5" className="fill-brand-600" />
      <circle cx="110" cy="154" r="11" className="fill-brand-600" />
      <circle cx="148" cy="58" r="19" strokeWidth="5" className="fill-danger stroke-primary-soft" />
      <path d="M145 53l4-3v17" strokeWidth="3.5" strokeLinecap="round" strokeLinejoin="round" fill="none" className="stroke-neutral-50" />
    </svg>
  );
}

function Dots({ step, total, className }: { step: number; total: number; className?: string }) {
  return (
    <div className={cn("flex gap-1.5", className)} role="img" aria-label={"Step " + (step + 1) + " of " + total}>
      {Array.from({ length: total }, (_, i) => (
        <span key={i} className={cn("h-1.5 rounded-full transition-all", i === step ? "w-[22px] bg-primary" : "w-1.5 bg-border-strong")} />
      ))}
    </div>
  );
}

/** Ask here first; call the system permission prompt only after "Allow". */
export default function AllowNotifications({ step = 2, total = 4, onAllow, onLater }: {
  step?: number;
  total?: number;
  onAllow?: () => void;
  onLater?: () => void;
}) {
  return (
    <main className="mx-auto flex min-h-dvh max-w-md flex-col bg-bg px-6 pb-8 pt-16 text-center font-sans text-fg">
      <div className="mx-auto mb-7 mt-3 grid size-48 place-items-center rounded-[28px] bg-primary-soft p-6">
        <Illustration />
      </div>
      <h1 className="text-[26px] font-semibold leading-8 tracking-tight">Stay in the loop</h1>
      <p className="mt-2.5 text-[15px] leading-[22px] text-fg-muted">Get a nudge when your order ships, arrives or needs your attention.</p>
      <Dots step={step} total={total} className="mb-6 mt-auto justify-center pt-6" />
      <button type="button" onClick={onAllow} className="h-[52px] w-full rounded-lg bg-primary text-[15px] font-semibold text-primary-fg hover:bg-primary-hover">
        Allow notifications
      </button>
      <button type="button" onClick={onLater} className="mt-1 h-12 w-full rounded-lg text-[15px] font-medium text-fg-muted hover:bg-surface-2">
        Not now
      </button>
    </main>
  );
}

The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.