🚀 Big News:Socket Has Acquired Secure Annex.Learn More
Socket
Book a DemoSign in
Socket

@thrylm/baqk

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@thrylm/baqk

Smart back navigation with state preservation for React apps

Source
npmnpm
Version
0.1.0
Version published
Weekly downloads
74
54.17%
Maintainers
1
Weekly downloads
 
Created
Source

baqk

Smart back navigation with state preservation for React apps.

npm license

The Problem

User filters a list, clicks into a detail page, hits back — filters are gone. history.back() can't carry state, and sessionStorage alone doesn't know which page to restore. baqk solves this with a hybrid navId + sessionStorage approach that preserves state, scroll position, and navigation context across any number of levels.

Install

npm install @thrylm/baqk

ESM-only. Requires react >= 18.

Quick Start

// app.tsx — wrap your app with the adapter
import { BaqkAdapter } from "@thrylm/baqk/adapters/react-router";

function App() {
  return (
    <BaqkAdapter>
      <Routes>{/* ... */}</Routes>
    </BaqkAdapter>
  );
}
// products.tsx — listing page
import { useBaqk } from "@thrylm/baqk";

function ProductList() {
  const { restoredState, saveState, navigateWithTrail } =
    useBaqk<{ filters: Filters }>();

  // Restore filters synchronously — no useEffect
  const [filters, setFilters] = useState(
    () => restoredState?.filters ?? defaultFilters,
  );

  function openProduct(id: string) {
    saveState({ filters });
    navigateWithTrail(`/products/${id}`, { label: "Products" });
  }

  return <FilteredList filters={filters} onSelect={openProduct} />;
}
// product-detail.tsx — detail page
import { useBaqk } from "@thrylm/baqk";

function ProductDetail() {
  const { goBack, hasTrail, previousEntry } = useBaqk({
    fallbackPath: "/products",
  });

  return (
    <div>
      <button onClick={() => goBack()}>
        {hasTrail ? `← ${previousEntry?.label}` : "← Products"}
      </button>
      {/* ... */}
    </div>
  );
}

Adapters

React Router

import { BaqkAdapter } from "@thrylm/baqk/adapters/react-router";

<BaqkAdapter>
  <RouterProvider router={router} />
</BaqkAdapter>

Next.js App Router

import { BaqkAdapter } from "@thrylm/baqk/adapters/next";

<BaqkAdapter>
  {children}
</BaqkAdapter>

TanStack Router

import { BaqkAdapter } from "@thrylm/baqk/adapters/tanstack";

<BaqkAdapter>
  <RouterProvider router={router} />
</BaqkAdapter>

Generic (any router)

import { BaqkAdapter } from "@thrylm/baqk";

<BaqkAdapter
  navigate={(path, options) =>
    options?.replace ? myRouter.replace(path) : myRouter.push(path)
  }
  getCurrentPath={() => window.location.pathname + window.location.search}
>
  {children}
</BaqkAdapter>

All router-specific adapters accept optional sessionKey and storage props. The generic adapter additionally requires navigate and getCurrentPath.

API Reference

useBaqk<T>(options?)

Options (BaqkOptions)

OptionTypeDefaultDescription
fallbackPathstringundefinedPath to navigate to when goBack() is called with no trail
autoSaveScrollbooleantrueAutomatically save/restore scroll position

Return value (BaqkResult<T>)

PropertyTypeDescription
restoredStateT | nullSynchronously available saved state (lazy ref pattern)
wasRestoredbooleanWhether state was restored for this page
saveState(state: T) => voidSave state for the current page
restoreState() => T | nullManually restore state (usually not needed — use restoredState)
navigateWithTrail(path, opts?) => voidNavigate to path, pushing the current page onto the trail
goBack(fallbackPath?) => voidPop the trail and navigate back, or use fallback
hasTrailbooleanWhether there are entries in the trail
previousEntryTrailEntry | nullThe most recent trail entry (the page you'd go back to)
trailreadonly TrailEntry[]The full trail stack
clearAll() => voidClear the trail and all associated state

TrailEntry

interface TrailEntry {
  path: string;
  navId: string;
  label?: string;
  timestamp: number;
}

navigateWithTrail options

OptionTypeDescription
labelstringLabel for the breadcrumb (e.g. "Products")
stateTState to save for the current page before navigating

BaqkAdapterProps (router-specific adapters)

PropTypeDescription
childrenReactNode
sessionKeystring?Namespace for storage isolation (e.g. user ID)
storageStorageAdapter?Custom storage backend (defaults to sessionStorage)

GenericBaqkAdapterProps (generic adapter)

Extends BaqkAdapterProps with:

PropTypeDescription
navigate(path: string, options?: { replace?: boolean }) => voidNavigation function
getCurrentPath() => stringReturns current path + search params

How It Works

  • Each page visit gets a unique navId stamped into history.state
  • When you call navigateWithTrail, the current page's path + navId are pushed onto a trail stack in sessionStorage
  • State and scroll position are keyed by sessionKey:navId, so they survive navigations
  • goBack pops the trail, navigates to the previous path, and re-stamps the navId — triggering automatic state + scroll restoration
  • restoredState is computed synchronously via a lazy ref (no useEffect, no flash of default state)

Advanced

Session key

Use sessionKey to isolate trails per user or session:

<BaqkAdapter sessionKey={user.id}>

Custom storage

import { createMemoryStorage } from "@thrylm/baqk";

<BaqkAdapter storage={createMemoryStorage()}>

createBaqkAdapter factory

Build an adapter for any router:

import { createBaqkAdapter } from "@thrylm/baqk";

const MyBaqkAdapter = createBaqkAdapter(() => {
  // Return a RouterAdapter: { getCurrentPath, navigate, getHistoryState, replaceHistoryState }
  return useMyRouter();
});

Limits

  • Trail stack: max 50 entries (oldest evicted with their state)
  • State size: max 100 KB per entry (oversized state is silently dropped with a console warning)

License

MIT

Keywords

react

FAQs

Package last updated on 13 Mar 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts