Skip to content

React hook

usePush from pushpilot/react takes a shared client and returns PushState. It uses useSyncExternalStore and starts the client in an effect. React 18 and 19 are supported.

'use client';
import { createPushClient } from 'pushpilot/client';
import { usePush } from 'pushpilot/react';
const client = createPushClient();
export function Notifications() {
const state = usePush(client);
if (state.status === 'needs-install')
return <p>Add this site to your Home Screen to receive notifications.</p>;
if (state.status === 'denied')
return <p>Allow notifications in your browser settings.</p>;
if (state.status === 'unknown' || state.status === 'unsupported') return null;
if (state.status === 'error')
return <button onClick={() => void client.sync()}>Retry setup</button>;
if (state.status === 'subscribed')
return (
<button onClick={() => void client.disable()}>
Disable notifications
</button>
);
return (
<button
disabled={state.status !== 'unsubscribed'}
onClick={() => void client.enable()}
>
Enable notifications
</button>
);
}

Create the client outside the component. Remounting then preserves reconciliation state without creating extra service-worker registrations. The server snapshot is unknown and never touches window.