# Routing Mechanisms in Stremio Web: Custom Hash-Based Router Implementation

> Explore Stremio Web routing mechanisms. Discover how a custom hash-based client-side router uses regex to match URLs and render React views without external libraries.

- Repository: [Stremio/stremio-web](https://github.com/Stremio/stremio-web)
- Tags: internals
- Published: 2026-05-23

---

**Stremio Web implements a lightweight, hash-based client-side router that matches URL hash fragments against regular expressions to extract parameters and render React views without relying on external routing libraries like react-router.**

The Stremio Web application (`Stremio/stremio-web`) manages navigation through a bespoke routing architecture built entirely within its `src/router` directory. This system parses `window.location.hash` to determine active views, matches paths against configured regular expressions, and manages view state through React context providers. Understanding these routing mechanisms is essential for developers customizing the Stremio interface or debugging navigation flows.

## Hash-Based Navigation and the Router Component

At the core of Stremio Web's routing lies the `Router` component defined in [`src/router/Router/Router.js`](https://github.com/Stremio/stremio-web/blob/main/src/router/Router/Router.js). This component registers a `hashchange` event listener on the global `window` object within a `useLayoutEffect` hook (lines 73‑78), enabling the application to respond to hash fragment changes without page reloads. When the hash changes, the `onLocationHashChange` handler (lines 21‑23) parses the pathname and instantiates a `URLSearchParams` object from the query string portion of the hash.

Unlike traditional HTML5 History API routers, this hash-based approach requires no server-side configuration to handle deep links. The router maintains an internal `views` state array that tracks the currently matched view configurations, updating this state only when `routeConfigForPath` successfully identifies a matching route pattern.

## Route Configuration and Pattern Matching

Routes in Stremio Web are defined through a `viewsConfig` prop passed to the `Router` component, structured as an array of view levels each containing `routeConfig` objects. Each configuration object specifies three properties: a `regexp` for path matching, an array of `urlParamsNames` corresponding to regex capture groups, and a `component` reference to render upon match. The PropTypes definition in [`src/router/Router/Router.js`](https://github.com/Stremio/stremio-web/blob/main/src/router/Router/Router.js) (lines 99‑105) enforces this contract, ensuring valid route configurations.

The actual matching logic resides in [`src/router/Router/routeConfigForPath.js`](https://github.com/Stremio/stremio-web/blob/main/src/router/Router/routeConfigForPath.js). This utility iterates through the `viewsConfig` array and returns the first `routeConfig` whose `regexp` matches the current pathname. If no match exists, the router invokes the optional `onPathNotMatch` callback (lines 24‑38), allowing the application to render fallback content or handle 404 scenarios gracefully.

## URL Parameter Extraction with urlParamsForPath

When a route matches, Stremio Web extracts dynamic parameters using the `urlParamsForPath` function from [`src/router/Router/urlParamsForPath.js`](https://github.com/Stremio/stremio-web/blob/main/src/router/Router/urlParamsForPath.js). This function maps the RegExp match result's captured groups into a structured object using the `urlParamsNames` defined in the route configuration. The resulting `urlParams` object always contains a `path` property representing the matched string, alongside key-value pairs for each named parameter.

For example, a route configured with `regexp: /^\/movie\/([^/]+)$/` and `urlParamsNames: ['id']` produces `urlParams` containing `{ path: '/movie/123', id: '123' }`. Combined with the `queryParams` `URLSearchParams` instance, view components receive complete access to both path segments and query string data.

## Navigation Lifecycle and Interception Hooks

Stremio Web's router provides fine-grained control over navigation through the `onRouteChange` callback prop. Before committing to a new view state, the router calls this function with the proposed route configuration, extracted `urlParams`, and `queryParams` (lines 45‑48). If `onRouteChange` returns a truthy value, the router aborts the standard view update, enabling custom navigation guards, analytics tracking, or conditional redirects.

This interception mechanism operates within the `onLocationHashChange` handler alongside the `onPathNotMatch` fallback. Developer-defined callbacks can inspect the proposed navigation and either allow the router to update its internal `views` array or handle the transition through alternative logic.

## View Rendering and Focus Management

Once the router determines the active view configuration, it renders the corresponding component wrapped in a `RouteFocusedProvider`. This provider, exported from [`src/router/RouteFocusedContext/RouteFocusedContext.js`](https://github.com/Stremio/stremio-web/blob/main/src/router/RouteFocusedContext/RouteFocusedContext.js), supplies a `routeFocused` boolean value indicating whether the view currently holds application focus. This context is critical for managing input handling, animation states, and media playback in stacked view architectures.

The public API surface in [`src/router/index.js`](https://github.com/Stremio/stremio-web/blob/main/src/router/index.js) exposes the `Router` component, `Modal` component for overlay dialogs, and the `useRouteFocused` hook for consuming focus state within child components. The `Modal` component integrates with the view stack without manipulating the underlying hash state, enabling modal interactions that preserve the current route context.

## Practical Implementation Examples

The following examples demonstrate how to configure and utilize Stremio Web's routing mechanisms:

```tsx
// Define route configurations with regex patterns and parameter names
const viewsConfig = [
  [
    {
      regexp: /^\/$/,
      urlParamsNames: [],
      component: Home,
    },
    {
      regexp: /^\/movie\/([^/]+)$/,
      urlParamsNames: ['id'],
      component: Movie,
    },
  ],
];

```

```tsx
// Implement the Router component with navigation callbacks
function App() {
  return (
    <Router
      viewsConfig={viewsConfig}
      onPathNotMatch={() => <NotFound />}
      onRouteChange={(route, urlParams, queryParams) => {
        console.log('Navigating to', route, urlParams, queryParams);
        // Return true to prevent the router from updating views
        return false;
      }}
    />
  );
}

```

```tsx
// Access extracted parameters within a view component
function Movie({ urlParams, queryParams }) {
  const movieId = urlParams.id; // Extracted from "#/movie/123"
  const startTime = queryParams.get('t'); // Value of "?t=5" if present
  
  return (
    <div>
      <h1>Movie {movieId}</h1>
      {startTime && <p>Resume from {startTime}</p>}
    </div>
  );
}

```

```tsx
// Fallback component for unmatched paths
function NotFound() {
  return <div>Content not available</div>;
}

```

## Summary

- **Hash-based architecture**: Stremio Web uses `window.location.hash` changes and a `hashchange` listener in [`src/router/Router/Router.js`](https://github.com/Stremio/stremio-web/blob/main/src/router/Router/Router.js) rather than the HTML5 History API, enabling deep linking without server configuration.
- **Regex-driven matching**: Routes define `regexp` patterns in `viewsConfig`, processed by `routeConfigForPath` to determine active views based on current hash paths.
- **Structured parameter extraction**: The `urlParamsForPath` function converts regex capture groups into named parameters accessible via `urlParams` props in view components.
- **Navigation interception**: The `onRouteChange` callback allows applications to intercept and conditionally prevent route updates before the router modifies its internal state.
- **Focus-aware rendering**: `RouteFocusedContext` provides focus state to nested components through `RouteFocusedProvider`, enabling sophisticated UI behaviors in multi-view layouts.
- **Modal support**: The `Modal` component exported from [`src/router/index.js`](https://github.com/Stremio/stremio-web/blob/main/src/router/index.js) renders overlay content without disrupting the underlying hash-based route state.

## Frequently Asked Questions

### How does Stremio Web handle 404 errors or unmatched routes?

When no configured route matches the current hash path, the `routeConfigForPath` function returns `null`, triggering the optional `onPathNotMatch` callback in [`src/router/Router/Router.js`](https://github.com/Stremio/stremio-web/blob/main/src/router/Router/Router.js) (lines 24‑38). Developers can supply a fallback component through this callback to render custom error pages or implement redirect logic when users navigate to undefined paths.

### Can I use query parameters in Stremio Web routes?

Yes, the router automatically parses the query string portion of the hash into a `URLSearchParams` instance passed as `queryParams` to view components. You can access these values using standard `URLSearchParams` methods like `.get('key')` within any component rendered by the router, regardless of the specific route configuration.

### What is the purpose of the RouteFocusedContext in Stremio Web?

`RouteFocusedContext` determines whether a rendered view currently holds application focus. Wrapped around each route via `RouteFocusedProvider` in [`src/router/RouteFocusedContext/RouteFocusedContext.js`](https://github.com/Stremio/stremio-web/blob/main/src/router/RouteFocusedContext/RouteFocusedContext.js), this context enables components to adjust behavior based on visibility—such as pausing media playback when a view loses focus or managing keyboard navigation scope in stacked interface layers.

### How do I prevent a route from changing in Stremio Web?

Return `true` from the `onRouteChange` callback prop passed to the `Router` component (lines 45‑48). This function receives the proposed route configuration, `urlParams`, and `queryParams` before the router updates its internal `views` state. Returning a truthy value aborts the navigation, allowing for conditional routing logic such as authentication checks or unsaved change warnings.