Does UI Kit 2 support custom URL routing with react-router?

Custom UI does support it but there’s no information if it would work with UI Kit 2.

Thanks!

Sorry for bumping an old thread - arrived here via Google since I was also seeking clarification on this topic.

In case this is helpful to others, I followed this guide and despite the focus being Custom UI I can confirm that it worked successfully for my UI Kit 2 app. Here’s the TypeScript code I ended up:

import { view } from "@forge/bridge";
import { useQuery } from "@tanstack/react-query";
import { type JSX, type PropsWithChildren, useEffect, useState } from "react";
import {
  type Location,
  NavigationType,
  type Navigator,
  type Path,
  Router,
  Routes,
  createPath,
} from "react-router";

type History = Awaited<ReturnType<typeof view.createHistory>>;

export const HistoryRouter = ({
  children,
  fallback,
}: PropsWithChildren<{ fallback: JSX.Element }>) => {
  const { history, historyState } = useHistory();

  if (!history || !historyState) return fallback;

  return (
    <Router
      navigator={getNavigator(history)}
      navigationType={getNavigationType(historyState.action)}
      location={getLocation(historyState.location)}
    >
      <Routes>{children}</Routes>
    </Router>
  );
};

const useHistory = () => {
  const { data: history } = useQuery({
    queryKey: ["view", "create-history"],
    queryFn: view.createHistory,
  });

  const [historyState, setHistoryState] =
    useState<Pick<History, "action" | "location">>();

  useEffect(() => {
    if (historyState || !history) return;

    setHistoryState({ action: history.action, location: history.location });
  }, [history, historyState]);

  useEffect(() => {
    if (!history) return;

    history.listen((location, action) => {
      setHistoryState({ action, location });
    });
  }, [history]);

  return { history, historyState };
};

const getNavigator = (history: History): Navigator => ({
  createHref: (to: string | Partial<Path>) =>
    typeof to === "string" ? to : createPath(to),
  go: history.go,
  push: history.push,
  replace: history.replace,
});

const getNavigationType = (action: History["action"]) => {
  switch (action) {
    case "POP":
      return NavigationType.Pop;
    case "PUSH":
      return NavigationType.Push;
    case "REPLACE":
      return NavigationType.Replace;
  }
};

const getLocation = (location: History["location"]): Partial<Location> => {
  const { key, ...rest } = location;
  return key !== undefined ? { ...rest, key } : rest;
};

which can be used like so:

<HistoryRouter fallback={<Spinner />}>
  <Route index element={<Home />} />
  <Route path="test" element={<Test />} />
</HistoryRouter>