PraxisJS

@praxisjs/router

Changelog for @praxisjs/router — client-side routing with @Router, @Route, @Lazy, @Params, and @Location.

@praxisjs/router

2.1.0

Named routes — give routes a name and navigate by name instead of hardcoding paths.

  • name?: string field on RouteDefinition and on the @Route({ path, name, meta }) options object
  • push({ name, params?, query?, hash? }) and replace({ name, ... }) — navigate by name; params are interpolated into the path pattern
  • router.resolvePath({ name, params? }) — convert a named target to a path string without navigating
  • NamedNavigationTarget and NavigationInput types exported from the package
  • <Link to={{ name, params?, query?, hash? }}>to prop now accepts string | NamedNavigationTarget

Route meta — attach arbitrary metadata to any route definition.

  • meta?: Record<string, unknown> field on RouteDefinition / @Route options
  • location().meta — current route meta object (defaults to {} when unset)
  • location().name — current route name (string | undefined)
  • router.meta — reactive Computed<RouteMeta> shorthand for location().meta
  • @Meta() — new field decorator; injects router.meta into any component field
  • useMeta() — composable returning router.meta
  • RouteMeta type exported from the package

Navigation lifecycle hooks — post-navigation callbacks for analytics, focus management, and side effects.

  • afterEnter?: (to, from) => void — per-route hook in RouteDefinition; fires after the component is resolved, before global afterEach handlers
  • router.afterEach(handler) — global hook; fires after every completed navigation (not called when beforeEnter blocks); returns an unregister function
  • Hook execution order: beforeEnter → component resolved → afterEnter → afterEach → scrollBehavior

Scroll restoration — configurable scroll behavior per navigation.

  • scrollBehavior?: ScrollBehavior option added to RouterOptions / createRouter / @Router
  • Receives (to, from, savedPosition)savedPosition is non-null on back/forward navigations
  • Return { top, left } to scroll to coordinates, { el } to scroll an element into view, or false to skip scrolling; can return a Promise
  • Scroll position of the departing page is automatically saved into history.state before each push(); restored via savedPosition on popstate
  • Exported: ScrollPosition, ScrollBehavior, SavedScrollPosition, RouterOptions

2.0.0

Breaking — route type aliases changed

RouteParams, RouteQuery, and RouteLocation are now signal/computed types. Field annotations no longer require importing Signal or Computed.

DecoratorBeforeAfter
@Params()Computed<RouteParams>RouteParams
@Query()Computed<RouteQuery>RouteQuery
@Location()Signal<RouteLocation>RouteLocation
@InjectLayout()Signal<RouteComponent | null>LayoutInstance

If you typed beforeEnter guards explicitly with the old RouteLocation, remove the annotation (TypeScript infers from context) or use Parameters<RouteDefinition['beforeEnter']>[0].

1.2.0

Optional route segments — append ? to any named segment to make it optional.

{ path: '/posts/:slug?', component: PostPage }
  • /posts/hello-worldparams().slug === 'hello-world'
  • /posts/params().slug === '' (absent segment defaults to empty string)

1.1.0

Breaking — API renames

ChangedBeforeAfter
Root app decorator@RouterConfig([...])@Router([...])
Router field decorator@InjectRouter() router!: Router@Router() router!: RouterInstance
Router class (type annotation)RouterRouterInstance
Class exportexport { Router }export { RouterInstance }

Layout system — routes can now declare a persistent shell component that wraps the matched page without re-mounting on navigation.

  • layout? property on RouteDefinition — attach a layout to any route directly; RouterView renders <Layout> around the matched page
  • Layout inheritance via children — when a route has child routes, its component automatically becomes the layout for all of them
  • <RouterOutlet> — new component for use inside layouts (StatelessComponent); reactively renders the current page without needing the children prop
  • @InjectLayout() — field decorator injecting RouterInstance.currentLayout as a reactive signal, following the same pattern as @Router(), @Params(), etc.
  • RouterInstance.currentLayout — reactive signal exposing the currently active layout component
  • Lazy layouts — layout: Lazy(() => import('./MyLayout')) works identically to lazy page components

@Router decorator (renamed from @RouterConfig) — now implemented with createClassDecorator and ClassBehavior, consistent with the rest of the decorator API. RouterBehavior.create() re-activates the correct router on each component instantiation, resolving singleton conflicts when multiple @Router-decorated classes share the same module scope (e.g. Storybook stories loaded together).

Navigation sequence — concurrent push() calls no longer race. A monotonic _navSeq counter ensures only the most recent navigation commits its result; stale in-flight resolutions are silently discarded.

1.0.13

Updated dependencies — @praxisjs/[email protected], @praxisjs/[email protected], @praxisjs/[email protected].

1.0.12

<Link> now accepts a style prop — both a CSS string (style="color:red") and a style object (style={styleObject}).

1.0.1

  • @Lazy inline fixLazy(() => import('./Page')) used directly in route definitions now renders correctly. The returned function was missing the __isLazy marker so the router treated it as a plain component
  • @Route co-location@RouterConfig now accepts classes decorated with @Route directly. The path is read from __routePath automatically — no { path, component } wrapper needed
  • Lazy-loaded pages must use export default class — the loader resolves module.default at runtime

1.0.0

Breaking — full decorator-based API

All functional routing APIs removed:

RemovedReplacement
createRouter()@RouterConfig on the root component
lazy()@Lazy decorator or Lazy() inline
useRouter()@Router() field decorator
useParams()@Params() field decorator
useQuery()@Query() field decorator
useLocation()@Location() field decorator

0.2.4

Bug fix: beforeEnter guards that return a redirect string no longer recurse infinitely. Navigation aborts after 10 redirect hops with a console warning.

0.2.0

Migrated to TC39 decorator context API. Introduced StatefulComponent / StatelessComponent.

0.1.0

Initial beta release.

On this page