Routing

Steroids allows you to define a unified routing tree for the entire project, which can be considered a sitemap.

In the project, the tree is usually defined in the routes/index.ts file, where the root route root represents the main page (usually with the address /), and the branches of the tree are defined through items. Each page is described by an object with the IRouteItem interface.

By setting up this route tree, you gain several advantages:

  • You can create links by route ID: <Link toRoute='root'>...</Link>.
  • You can select a slice of the tree and render navigation based on it: <Nav items='profile'/>.
  • Link labels and page titles will be taken from the described route tree.
  • The relative path to pages – URL, is only described in the route tree, making it easy to change without refactoring the project.
  • Developers can visually see the entire project map by simply opening this file.
  • Roles can be specified for routes – roles, to restrict access to a page based on user roles.

An example of a route tree with three pages - the main page and profile pages:

import IndexPage from './IndexPage';
import ProfileGeneral from './ProfileGeneral';
import ProfileSettings from './ProfileSettings';
import { IRouteItem } from '@steroidsjs/core/ui/nav/Router/Router';

export const ROUTE_ROOT = 'root';
export const ROUTE_PROFILE = 'profile';
export const ROUTE_PROFILE_GENERAL = 'profile_general';
export const ROUTE_PROFILE_SETTINGS = 'profile_settings';

export default {
    id: ROUTE_ROOT,
    exact: true,
    path: '/',
    label: __('Main Page'),
    component: IndexPage,
    roles: [null, 'user'], // visible to guests and authenticated users
    items: {
        [ROUTE_PROFILE]: {
            label: __('Profile'),
            path: '/profile',
            redirectTo: true,
            roles: ['user'], // visible only to authenticated users
            items: {
                [ROUTE_PROFILE_GENERAL]: {
                    label: __('General Information'),
                    path: '/general', // specify only the path segment, the rest will be added from the parent
                    component: ProfileGeneral,
                    // roles are not specified here, they are inherited from the parent
                },
                [ROUTE_PROFILE_SETTINGS]: {
                    label: __('Settings'),
                    path: '/settings',
                    component: ProfileSettings,
                },
            },
        },
    },
} as IRouteItem;

Relative and Absolute Paths

By default, for nested routes, you only need to specify the path segment, and the full path will automatically be formed by appending the parent path segment.

For example:

// src/routes/index.ts
import {IRouteItem} from '@steroidsjs/core/ui/nav/Router/Router';
import IndexPage from './IndexPage';
import LoginPage from './LoginPage';
import SignUpPage from './SignUpPage';

export const ROUTE_ROOT = 'root';

const roles = [null];

export default {
    id: ROUTE_ROOT,
    exact: true,
    path: '/',
    component: IndexPage,
    roles,
    items: {
        auth: {
            exact: true,
            path: '/auth',
            roles,
            items: {
                login: {
                    exact: true,
                    path: '/login', 
                    roles,
                    component: LoginPage,
                }, // LoginPage will be accessible at URL /auth/login
                signUp: {
                    exact: true,
                    path: '/sign-up',
                    roles,
                    component: SignUpPage
                } // SignUpPage will be accessible at URL /auth/sign-up
            }
        }
    }
} as IRouteItem;

To use a route tree with absolute paths, add the alwaysAppendParentRoutePath flag to routerProps in the Application.tsx file:

// src/Application.tsx
import useApplication from '@steroidsjs/core/hooks/useApplication';

export default function Application() {
    const {renderApplication} = useApplication({
        routerProps: {
            alwaysAppendParentRoutePath: false, // specify the flag to use absolute paths
        },
        /* ... */
    });

    return renderApplication();
}

Then, to access the login and registration pages at the same URLs as in the previous example, you need to adjust the route tree structure to:

// src/routes/index.ts
import {IRouteItem} from '@steroidsjs/core/ui/nav/Router/Router';
import IndexPage from './IndexPage';
import LoginPage from './LoginPage';
import SignUpPage from './SignUpPage';

export const ROUTE_ROOT = 'root';

const roles = [null];

export default {
    id: ROUTE_ROOT,
    exact: true,
    path: '/',
    component: IndexPage,
    roles,
    items: {
        auth: {
            exact: true,
            path: '/auth',
            roles,
            items: {
                login: {
                    exact: true,
                    path: '/auth/login', // Specify the absolute path
                    roles,
                    component: LoginPage,
                }, // LoginPage will be accessible at URL /auth/login
                signUp: {
                    exact: true,
                    path: '/auth/sign-up', // Specify the absolute path
                    roles,
                    component: SignUpPage
                } // SignUpPage will be accessible at URL /auth/sign-up
            }
        }
    }
} as IRouteItem;

Route Settings

The path and exact parameters are passed directly to React Router. You can find their descriptions in the official documentation: React Router.

Name and Label

For each route, you can provide a label and title. The application can decide how to use them, but the initial intention is that label is used for link names, and title is used for page titles (and if not provided, label is used).

Redirect

To automatically redirect a route to another page, you need to set the redirectTo property, specifying the path to the page.

For example:

// src/routes/index.ts
import {IRouteItem} from '@steroidsjs/core/ui/nav/Router/Router';
import IndexPage from './IndexPage';
import LoginPage from './LoginPage';
import SignUpPage from './SignUpPage';

export const ROUTE_ROOT = 'root';

const roles = [null];

export default {
    id: ROUTE_ROOT,
    exact: true,
    path: '/',
    component: IndexPage,
    roles,
    items: {
        auth: {
            exact: true,
            path: '/auth',
            roles,
            redirectTo: '/auth/login', // Specifies the link to which the user will be automatically redirected when trying to access /auth
            items: {
                login: {
                    exact: true,
                    path: '/login', 
                    roles,
                    component: LoginPage,
                },
                signUp: {
                    exact: true,
                    path: '/sign-up',
                    roles,
                    component: SignUpPage
                }
            }
        }
    }
} as IRouteItem;

It is often necessary to redirect to a child page of a section. For example, as in the previous example, to make /auth redirect to /auth/login, where login is one of the child pages of the auth. In such cases, you can set redirectTo to true to redirect to the first child route.

// src/routes/index.ts
import {IRouteItem} from '@steroidsjs/core/ui/nav/Router/Router';
import IndexPage from './IndexPage';
import LoginPage from './LoginPage';
import SignUpPage from './SignUpPage';

export const ROUTE_ROOT = 'root';

const roles = [null];

export default {
    id: ROUTE_ROOT,
    exact: true,
    path: '/',
    component: IndexPage,
    roles,
    items: {
        auth: {
            exact: true,
            path: '/auth',
            roles,
            redirectTo: true, // Note that it is not necessary to specify a link if you want to redirect to the first route in items
            items: {
                login: {
                    exact: true,
                    path: '/login', 
                    roles,
                    component: LoginPage,
                },
                signUp: {
                    exact: true,
                    path: '/sign-up',
                    roles,
                    component: SignUpPage
                }
            }
        }
    }
} as IRouteItem;