Skip to content
Orbix React · Bootstrap 5 v1.0.3

Adding a page and a menu item

Add a page

1. Create the component src/pages/reports/sales.tsx:

import PageHeader from '@/components/shell/PageHeader';
import { useI18n } from '@/hooks/useI18n';
import { usePageScript } from '@/hooks/usePageScript';

export default function ReportsSalesPage() {
  const { t } = useI18n();
  usePageScript();
  return (
    <>
      <PageHeader title="reports.sales.title" subtitle="reports.sales.subtitle" section="nav.reports" sectionHref="/reports/sales" />
      <div className="fd-page">
        <section className="fd-card">
          <div className="fd-card__body">
            <p data-i18n="reports.sales.empty">{t('reports.sales.empty')}</p>
          </div>
        </section>
      </div>
    </>
  );
}

2. Register the route in src/app/pages.ts:

{ path: '/reports/sales', id: 'reports-sales', title: 'reports.sales.title', layout: 'app', load: () => import('@/pages/reports/sales') },
FieldMeaning
pathURL of the page (relative to the base path)
idPage id: marks the current menu entry (the menu entry with the same id)
titleTranslation key of the document title (… · Orbix)
layoutapp, auth (plus variant) or blank
attrsOptional attributes set on <html> while the page is shown
loadThe page component, loaded on demand (its own JavaScript chunk)

3. Add the texts to every src/locales/<locale>/ folder, for example a new reports.json (see Languages):

{
  "sales": {
    "title": "Sales report",
    "subtitle": "Revenue by channel and region",
    "empty": "No sales in this period yet."
  }
}

4. Optional page script. Code that works on the rendered markup (third-party widgets, charts, timers) goes in a function passed to usePageScript(). It runs after render; listeners on document/window added with listen(), timers added with every() and charts are released when the page unmounts:

// src/scripts/reports.ts
import { listen } from '../core/scope';

export function init(): void {
  listen(document, 'keydown', (event) => {
    if (event.key === 'r' && event.altKey) document.querySelector<HTMLButtonElement>('[data-report-refresh]')?.click();
  });
}
import { init } from '@/scripts/reports';
// ...
usePageScript(init);

For state that belongs to React (filters, lists, forms), use regular React state and hooks inside the component.

Visit http://localhost:5173/reports/sales.

Pages that need real data fetch it from your API in the component (for example with useEffect or a data library such as TanStack Query) and render it with the same markup.

Add a menu item

The sidebar, the horizontal menu, the two-column rail and the command palette are all built from src/app/menu.ts. Sections hold items and groups; groups hold children:

{
  id: 'reports',
  key: 'nav.reports',                  // section title (translation key)
  icon: 'lc-chart-column',
  items: [
    { id: 'reports-sales', to: '/reports/sales', key: 'nav.sales_report', icon: 'lc-chart-line' },
    {
      id: 'reports-more',
      key: 'nav.more_reports',
      icon: 'lc-folder-open',
      children: [{ id: 'reports-stock', to: '/reports/stock', key: 'nav.stock_report' }],
    },
  ],
},
KeyMeaning
idUnique navigation id; the page with the same id marks the entry as current and opens its group
toRoute path of the page
keyTranslation key of the label
iconIcon id in the sprite: lc-* (Lucide), tb-* (Tabler), fd-i-* or ox-i-* (Orbix)
badgeOptional counter: { count: 4, tone: 'primary' }

Use React Router's <Link to="/reports/sales"> for links between pages. Plain <a href> links created at runtime (for example inside a data grid cell) are handled by the router too, so the app never reloads.

Icons

Use any icon of the bundled sets with an SVG <use> reference:

<svg className="fd-icon" aria-hidden="true"><use href="#lc-chart-line" /></svg>

Browse the sets on the Icons pages of the template. Only the icons you reference are included in the sprite: after adding a new lc-* or tb-* icon, run npm run assets (it also runs with npm run dev, npm run build and npm test).