> For the complete documentation index, see [llms.txt](https://webcomp.gitbook.io/webcomp/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://webcomp.gitbook.io/webcomp/routing.md).

# Routing

Routing in your components is possible via `@webcomp/router` module.

WebComp router is a modern client side router that provides Express-like route handling, supports history API and hash mode and provides some higher order helpers. Let's go through everything.

## Basic usage

Here's how you can define routes in your component:

```jsx
import { WebComponent } from '@webcomp/core';
import { Router } from '@webcomp/router';

class MyElement extends WebComponent{
  componentDidMount = () => {
    Router.on('/profile/:id', this.handleRouteChange);
  }

  handleRouteChange = (url) => {
    console.log('Route changed! ID:', url.params.id); // "Route changed! ID: 123"
  }

  changeRoute = () => {
    Router.push('/profile/123');
  }

  render() {
    return <button onClick={this.changeRoute}>Change Route</button>
  }
}
```

Your route handler function will receive a `url` object with the following structure:

* **`params`**  - object with url params
* &#x20;**`path`** - Full path string
* &#x20;**`query`** - Parsed object from query string

## Router Methods and Properties

Besides `push` and `on` that we've already seen, router provides a few additional methods and configuration options.

### `Router.mode`

* Default: `hash`

A string indicating router's operation mode. Can be `hash` or `history`. To configure router for a different mode, assign a new value to it:

```javascript
Router.mode = 'history';
```

Keep in mind that this will configure the entire router, so you should only do it once at the **top level** of your app (before you register any of your components).

### `Router.root`

* Default: `/`

A string indicating router's root path. Same as with mode, you can assign a new value to set it:

```javascript
Router.root = '/settings';
```

This should also be configured once at the top level of your app.

### `` `on(route, handlerFunction, persist)` ``

Define a new handler for a route. Optional `persist` argument will prevent a handler from flushing if `Router.flushHandlers` is called.

Calling `Router.on` will return a string ID which you can use to remove handlers later if needed. Usage:

```javascript
Router.on('/profile/:id', (url) => {
  console.log(url.params.id);
})
```

### `removeHandler(id)`

Removes previously defined route handler by it's ID. Usage:

```javascript
Router.removeHandler('_mp6vmcfda');
```

### `flushHandlers()`

Removes all handlers from the router except ones that were defined with `persist` flag.

### `dangerouslyFlushRouter()`

Completely resets router to it's default state. Root is set to `'/'`, mode to `'hash'` and **all** route handlers are removed (even persisted ones).

You will most likely never need to use this method. If you must, use with caution.

### push(path)

Navigate to a new route. Uses \`pushState\` when in \`history\` mode. Usage:

```javascript
Router.push('/path/to/something');
```

### `replace(path)`

Navigate to a new route and replace the history state instead of pushing.\
\&#xNAN;***Note:** Only available in `history` mode.*

## `Routerize` decorator

Defining routes explicitly isn't always convenient. Some times you just want to watch what happens and do stuff based on that. For these use cases, WebComp provides a **`@routerize`** decorator:

```jsx
import { WebComponent } from '@webcomp/core';
import { routerize } from '@webcomp/router';

@routerize
class MyElement extends WebComponent{
  render(props) {
    // props.router.state is the same object that is passed to route handlers
    return <h1>Hello route {props.router.state.path}</h1>
  }
}
```

Here's the structure of `this.props.router` prop that `@routerize` gives you:

```javascript
{
  on(),
  push()
  replace(),
  flushHandlers(),
  dangerouslyFlushRouter(),
  root,
  state: {
    path,
    params: {},
    query: {},
  },
}
```

This will be updated on every route change, so you can rely on the prop directly, without needing to specify route handlers.

***Note:** Due to how router works by default, your component will be re-rendered on mount when routerized. It's usually not a big deal, but if it is, you should use  a custom router (see below) with a `skipInitial` option.*

## \<Route /> Component

If you only need to watch routes to change your rendered content, you can use `<Route />` component to do that:

```jsx
import { WebComponent } from '@webcomp/core';
import { Route } from '@webcomp/router';

class MyElement extends WebComponent{
  render(props) {
    return (
      <div>
        <Route path="/">
          <h1>Home Page</h1>
        </Route>
        <Route path="/settings">
          <h1>Settings</h1>
        </Route>
      </div>
    )
  }
}
```

### Shallow routes

Besides child node, `Route` also supports passing a \`component\` prop for render. If you do this, rendered component will automatically be routerized. You can bypass this behavior by using **`shallow`** prop.

```jsx
import { WebComponent } from '@webcomp/core';
import { Route } from '@webcomp/router';
import FancyHeader from './FancyHeader';

class MyElement extends WebComponent{
  render(props) {
    return (
      <div>
        <Route path="/" component={FancyHeader} />
        <Route path="/settings" component={FancyHeader} shallow />
      </div>
    )
  }
}
```

In the above example, `FancyHeader` component on route `/` will get `this.props.router`, but the one on `/settings` route won't.

## Advanced Usage

### Custom Routers

In some cases you need to have different router configurations for different components. WebComp allows you to create custom routers for this.

Default `Router` is an instance of a `WCRouter` class, which you can reuse or extend.

```javascript
import { WCRouter } from '@webcomp/router';

class SafeRouter extends WCRouter {
  constructor(options) {
    super(options);

    this.dangerouslyFlushRouter = () => throw new Error("Safe router doesn't allow flushing");
    this.flushHandlers = () => throw new Error("Safe router doesn't allow flushing");
  }
}

const MyCustomRouter = new SafeRouter({ skipInitial: true, mode: 'history' });
```

### Custom router options

* **`skipInitial`** - If this is set, router won't fire handlers on initial page load.
* **`mode`** - Set default mode. Can be `'hash'` or `'history'`.
* **`root`** - Set custom default root

### Routerizing with custom router

The `@routerize` decorator uses default router instance. If you want to routerize your component with your custom router, you can use **`routerizeWith`** decorator instead:

```javascript
import { WebComponent } from '@webcomp/core';
import { WCRouter, routerizeWith } from '@webcomp/router';

const CustomRouter = new WCRouter({ skipInitial: true });

@routerizeWith(CustomRouter)
class MyElement extends WebComponent{
  render(props) {
    return <h1>...</h1>
  }
}
```

### Using custom routers with `<Route />`

You can also use custom routers with `<Route />` component by providing it as a **`customRouter`** prop:

```jsx
import { WebComponent } from '@webcomp/core';
import { WCRouter, Route } from '@webcomp/router';
import FancyHeader from './FancyHeader';

const MyRouter = new WCRouter({ skipInitial: true });

class MyElement extends WebComponent{
  render(props) {
    return (
      <div>
        <Route path="/" component={FancyHeader} customRouter={MyRouter} />
      </div>
    )
  }
}
```
