Routes and navigation

Every file under routes/ is a page: routes/index.tsx is /, routes/experiences/[id].tsx is /experiences/:id, and routes/_layout.tsx wraps the routes below it. A route exports its meta (who may open it, the row it is about, its title and SEO) and a default React component.

@appbricx/ui10 membersSDK referenceProject files: routes

On this page
  1. Route meta
  2. defineRoute
  3. Links and navigation
  4. <Link>
  5. <NavLink>
  6. useNavigate
  7. useParams
  8. useSearchParams
  9. useRoute
  10. useLocation
  11. useCanOpen
  12. Errors
  13. <ErrorBoundary>
  14. Types

Route meta is plain data the platform reads when it checks the project: it decides who may open the page (public, or a list of roles), server-renders public pages with what a signed-out visitor may read, writes the head from the row and lists the page in the sitemap.

Navigation is client-side: Link and useNavigate move without a page load, and NavLink hides a link the signed-in user's role may not open.

Route meta

defineRoutefunction

Declares a route's meta: public (signed-out visitors may open it; it is server-rendered and in the sitemap), roles (who may open it; default any signed-in role), title, row (the row the page is about, found by the route's last parameter) and seo (title, description, image, JSON-LD and sitemap filter, as templates over the row).

defineRoute(meta: RouteMeta): RouteMeta

Parameters

NameTypeDescription
metarequiredRouteMetaPlain data: no functions, no values computed at runtime.
Returns
The same object (typed).
Errors
Does not throw.
Permissions
A visitor who may not open the route gets the sign-in screen; a public route whose row a guest can't read answers 404.
Example
// routes/experiences/[id].tsx
import { defineRoute, useRow } from "@appbricx/ui";

export const meta = defineRoute({
  public: true,
  row: { table: "experience" },            // bound by :id
  seo: {
    title: "{{title}} · Teamday",
    description: "{{title}} in {{city}}",
    sitemap: { where: { status: "published" } },
  },
});

export default function Experience() {
  const { row, notFound } = useRow("experience");
  if (notFound) return <main>No such experience.</main>;
  if (!row) return <main>Loading…</main>;
  return <h1>{row.title}</h1>;
}

Source: internal/kernel/appsdk/ui/meta.ts:32

An in-app link: a normal <a href> that moves without a page load (a modified click, target or another site falls back to the browser).

Link({ to, replace, onClick, ...rest }: LinkProps): Element

Parameters

NameTypeDescription
{ to, replace, onClick, ...rest }requiredLinkProps
Returns
Element
Errors
Does not throw.
Permissions
None: whether the target opens is decided by its route's meta.
Example
import { Link } from "@appbricx/ui";

<Link to={"/experiences/" + row.id}>{row.title}</Link>

Source: internal/kernel/appsdk/ui/router.tsx:226

A Link that renders nothing when the signed-in user's role may not open its target (navigation menus). Signed-out visitors still see it, so they can follow it to sign in.

NavLink(props: LinkProps): Element | null

Parameters

NameTypeDescription
propsrequiredLinkProps
Returns
Element | null
Errors
Does not throw.
Permissions
Hides, never protects: the route's own meta is what refuses.
Example
import { NavLink } from "@appbricx/ui";

<nav>
  <NavLink to="/bookings">Bookings</NavLink>
  <NavLink to="/ops">Ops desk</NavLink>   {/* only ops see it */}
</nav>

Source: internal/kernel/appsdk/ui/app.tsx:464

useNavigatefunction

A function that moves to another path without a page load; replace: true replaces the history entry. Use it instead of writing to location (the lint refuses that).

useNavigate(): (to: string, opts?: { replace?: boolean }) => void
Returns
(to: string, opts?: { replace?: boolean }) => void
Errors
Does not throw.
Permissions
None.
Example
const navigate = useNavigate();
const r = await confirmBooking({ booking: id });
navigate("/bookings?done=" + r.ref, { replace: true });

Source: internal/kernel/appsdk/ui/router.tsx:212

useParamsfunction

The current route's parameters, named after the brackets in the file name: routes/[city]/experiences/[slug].tsx gives { city, slug }.

useParams<P extends Record<string, string> = Record<string, string>>(): P
Returns
P
Errors
Does not throw.
Permissions
None. Parameters come from the URL: treat them as untrusted input.
Example
const { slug } = useParams<{ slug: string }>();
const { rows } = useQuery("experience", { where: { slug }, limit: 1 });

Source: internal/kernel/appsdk/ui/router.tsx:197

useSearchParamsfunction

The query string as URLSearchParams.

useSearchParams(): URLSearchParams
Returns
URLSearchParams
Errors
Does not throw.
Permissions
None. Values are untrusted input.
Example
const q = useSearchParams().get("q") ?? "";

Source: internal/kernel/appsdk/ui/router.tsx:207

useRoutefunction

The current route: path, search, params and its meta.

useRoute(): RouteState
Returns
RouteState
Errors
Does not throw.
Permissions
None.
Example
const { path, meta } = useRoute();
document.title = meta.title ?? path;

Source: internal/kernel/appsdk/ui/router.tsx:202

useLocationfunction

The current { path, search }, re-rendering on every navigation (also outside a route, in a layout).

useLocation(): Location
Returns
Location
Errors
Does not throw.
Permissions
None.
Example
const { path } = useLocation();
const active = path.startsWith("/bookings");

Source: internal/kernel/appsdk/ui/router.tsx:184

useCanOpenfunction

Whether the signed-in user may open a path: a public route, a route their role is in, or any route for a signed-out visitor (who may follow it to sign in).

useCanOpen(path: string): boolean

Parameters

NameTypeDescription
pathrequiredstring
Returns
boolean
Errors
Does not throw.
Permissions
A hint for the UI; the route's meta is what the server enforces.
Example
const canOps = useCanOpen("/ops");
return canOps ? <OpsShortcuts /> : null;

Source: internal/kernel/appsdk/ui/app.tsx:454

Errors

<ErrorBoundary>component

Catches a render error below it so the rest of the page keeps working; fallback draws the message, resetKey clears it when it changes. Every route and layout is already wrapped in one, so a broken page never takes the navigation with it.

<ErrorBoundary {...{ children?: ReactNode; resetKey?: string; fallback?: (e: Error) => ReactNode }} />
Returns
ReactNode
Errors
Does not throw.
Permissions
None.
Example
<ErrorBoundary resetKey={id} fallback={(e) => <p role="alert">Couldn't show the chart: {e.message}</p>}>
  <BookingsChart id={id} />
</ErrorBoundary>

Source: internal/kernel/appsdk/ui/app.tsx:485

Types

interface RouteMeta {
  /** Open to signed-out visitors (server-rendered, in the sitemap). */
  public?: boolean;
  /** The roles that may open it; default: any signed-in role. */
  roles?: string[];
  /** The page's title (also the browser tab's). */
  title?: string;
  /**
   * The row this page is about: { table, by } binds the route's last parameter (or `param`) to the
   * column `by` (default "id"), which finds the row. `params` binds the route's other parameters, so
   * the sitemap can list a URL per row: a column of the row, or "<ref column>.<column>" through a
   * reference — `/[city]/experiences/[slug]`: `{ table: "experience", by: "slug", params: { city: "city.slug" } }`
   * (the row's `city` column references city; the URL shows that city's `slug`).
   */
  row?: { table: string; by?: string; param?: string; params?: Record<string, string> };
  /** The head, as templates over the row's fields: "{{title}} · Teamday". */
  seo?: {
    title?: string;
    description?: string;
    image?: string;
    /** Structured data: one object or several (a Product and its BreadcrumbList). */
    jsonld?: Record<string, unknown> | Record<string, unknown>[];
    noindex?: boolean;
    /** Which rows the sitemap lists: { where: { status: "published" } }. */
    sitemap?: { where?: Record<string, string | number | boolean> };
  };
}

Source: internal/kernel/appsdk/ui/meta.ts:4

interface RouteState {
  path: string;
  search: string;
  params: Record<string, string>;
  meta: RouteMeta;
}

Source: internal/kernel/appsdk/ui/router.tsx:175

interface LinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
  to: string;
  replace?: boolean;
}

Source: internal/kernel/appsdk/ui/router.tsx:220