PushPermissionPrompt
A dismissible prompt that asks the user to enable push notifications, then registers the VAPID subscription with your server.
01 Usage
Basic
Enable push notifications?
<script lang="ts">
import { PushPermissionPrompt } from '@urbicon-ui/auth';
</script>
<PushPermissionPrompt vapidPublicKey="BExample...base64-encoded-vapid-public-key" />
02 Accessibility
It never interrupts
The prompt is an ordinary card in the flow, not a modal: it keeps focus where it was on mount, and both actions are buttons, so a user can read it, act on it, or ignore it when they reach it.
Failures are announced, dismissals are not
The role="alert" region inside the card is always mounted
while the prompt is visible, so a rejected VAPID key, a conflicting endpoint or a rate limit
is announced in place and the prompt stays open to retry. A denied browser permission is not
an error and closes the prompt instead.
Focus is handed on when the card closes
Enabling or dismissing unmounts the whole card, so the button that was pressed goes with it and the next Tab would otherwise start over at the top of the page. The prompt moves focus to the element that held it when the prompt appeared; if that element is gone, to the next tab stop after the card; failing that, to the one before it. Controls that are disabled or not rendered are skipped, and nothing outside the card is modified on the way — no page heading is made focusable to catch the ring. A page whose only controls were inside the card keeps none, so focus lands where the browser puts it.
Your callback runs first. onDismissed, onSubscribed and onUnavailable are called before the prompt looks for
a landing spot, and it only moves focus that is still on its own two buttons — so a callback
that places focus itself wins, and so does a user who clicked elsewhere while the request ran.
03 API Reference
Prop | Type | Default | Description | |
|---|---|---|---|---|
vapidPublicKey required | string | — | VAPID public key for push subscription. | |
apiPath | string | '/api/notifications/push-subscription' | API endpoint for registering subscriptions. | |
class | string | — | Extra classes on the root element. | |
csrf | CsrfClientOptions | — | CSRF cookie/header names. Only needed when the server overrides the defaults via config.csrf. Mutating requests echo the token automatically. | |
fetcher | typeof globalThis.fetch | — | Custom fetch implementation for all API calls. Defaults to the global fetch. Useful for mock backends in demos/tests or custom retry/auth layers. | |
onDismissed | () => void | — | Called when the user dismisses the prompt. | |
onSubscribed | (subscription: PushSubscription) => void | — | Called after successful push subscription. | |
onUnavailable | (reason: 'denied' | 'unsupported') => void | — | Called when the prompt closes because push is not available: the user
declined the browser permission ('denied') or the browser has no push
support ('unsupported'). Persist this to avoid remounting the prompt on
every visit; without it, a denial is indistinguishable from never having
shown the prompt. Operational failures do not close the prompt; they show
the error state instead. | |
preset | string | — | Apply a named preset registered via <BlocksProvider presets={{ PushPermissionPrompt: { … } }}>.
Resolves after the provider defaults and before this instance's own
slotClasses, so a project-wide look lives in one place instead of being
repeated at every usage site. | |
slotClasses | Partial<Record<'root' | 'text' | 'error' | 'actions', string>> | — | Per-slot class overrides. error styles the error Alert itself — present
only while an error is shown — not the live region that always surrounds
it (the same contract as every other component's error slot). | |
t | PartialAuthLocale | — | Locale overrides, deep-merged over the bundle registered for the active
locale — English unless registerAuthLocale ran for it. Pass any subset,
from a single string to a whole tree. | |
unstyled | boolean | — | Strip all default styling. |
04 Types
Local type definitions used by this component.
Name | Kind | Category | Used by | Description | |
|---|---|---|---|---|---|
PushPermissionPromptProps | interface | props | 0 | — | |
PartialAuthLocale | type | helper | 1 | Consumer-facing locale input: any subset of AuthLocale. Components
accept this as their t prop and deep-merge it over the bundle registered
for the active locale — English unless registerAuthLocale ran for it — so
overriding a single string never silently blanks the rest. | |
CsrfClientOptions | interface | helper | 1 | — | |
DeepPartial | type | helper | 0 | Recursive partial: every branch and leaf becomes optional. | |
AuthLocale | interface | helper | 0 | The complete auth locale bundle. Every key is required: the bundles this
package ships (en, de) satisfy the full shape, and consumer overrides
enter as PartialAuthLocale, deep-merged by mergeAuthLocale over the
bundle registered for the active locale — English unless registerAuthLocale
ran for it — so component markup reads keys directly, without per-key
?? '…' fallback literals.
Placeholder convention: dynamic values use **single-brace** tokens
({n}, {name}, {email}) that the consuming component substitutes itself
via String.replace('{token}', value). There is deliberately **no**
{{…}} runtime interpolator in this package. The key-based translator twin
(authT/at) was removed, so {{…}} here would render verbatim. |
05 Installation
Import
import { PushPermissionPrompt } from '@urbicon-ui/auth';