Skip to content

Tutorial — your first session ​

Observe browser state first — install, start a session, subscribe to events, read the snapshot, dispose. Optional session intelligence and DX come later (zero-cost until you ask).

Progressive path: Basic (this page) → Concepts → Visibility / Events.

Previous: Core concepts · Next: Visibility

Playground

Visibility explorer — switch tabs and observe event order.

Prerequisites: Node 20+, browser or SSR-aware bootstrap.

Learning path ​

LevelDocPlayground
BasicThis tutorialVisibility
IntermediateEvents · Session coreEvents · Lifecycle
ProductionCore infrastructure · UsageConfiguration

Step 1 — Install ​

bash
npm install @jayoncode/browser-lifecycle

Outcome: Package available for import.


Step 2 — Create a session ​

ts
import { createBrowserLifecycle } from "@jayoncode/browser-lifecycle";

const lifecycle = createBrowserLifecycle({ autoStart: true });

Outcome: Session in running phase with modules attached per configuration.


Step 3 — Subscribe to events ​

ts
lifecycle.on("page:visible", () => {
  resumePolling();
});

lifecycle.on("page:hidden", () => {
  pausePolling();
});

Outcome: Handlers run on normalized visibility transitions. Unsubscribe via returned function.


Step 4 — Read snapshot ​

ts
const snapshot = lifecycle.getSnapshot();
console.log(snapshot.visibility); // "visible" | "hidden" | "unknown"

Outcome: Readonly view of current session state without manual listener bookkeeping.


UI structure (framework shell) ​

Browser Lifecycle has no form markup — mount one shared session and dispose on unmount.

React JSX ​

tsx
import { useEffect, useMemo } from "react";
import { createBrowserLifecycle } from "@jayoncode/browser-lifecycle";

export function AppShell({ children }: { children: React.ReactNode }) {
  const lifecycle = useMemo(() => createBrowserLifecycle({ autoStart: true }), []);

  useEffect(() => {
    const offVisible = lifecycle.on("page:visible", () => resumeWork());
    const offHidden = lifecycle.on("page:hidden", () => pauseWork());

    return () => {
      offVisible();
      offHidden();
      lifecycle.dispose();
    };
  }, [lifecycle]);

  return <>{children}</>;
}

Vanilla HTML + module script ​

html
<body>
  <main id="app"><!-- your UI --></main>
  <script type="module">
    import { createBrowserLifecycle } from "@jayoncode/browser-lifecycle";

    const lifecycle = createBrowserLifecycle({ autoStart: true });
    lifecycle.on("page:hidden", () => console.log("tab hidden"));

    window.addEventListener("pagehide", () => {
      lifecycle.dispose();
    });
  </script>
</body>

Step 5 — Dispose ​

ts
lifecycle.dispose();

Outcome: Listeners removed (sync); instance must not be reused.


Recap ​

StepAPIResult
1npm installDependency installed
2createBrowserLifecycle()Active session
3on(event, handler)Typed subscriptions
4getSnapshot()Current state
5dispose()Clean teardown

Pitfalls ​

IssueMitigation
Multiple sessions per tabSingle shared instance
Missing teardownCall dispose() on unmount
SSR accessGuard typeof window !== "undefined"

Continue ​

TopicGuidePlayground
Visibility moduleVisibilityVisibility
Event patternsEventsEvents
Config & SSRCore infrastructureConfiguration

Quick start · FAQ

An ecosystem of independent, headless TypeScript libraries engineered for modern web development. Every package includes interactive playgrounds and documentation that evolves alongside the code.