redpanda-data/ui-harness · Archived

setup-tanstack-router

Auto-generate TanStack Router route tree and enforce router patterns via PostToolUse hooks. Bans react-router-dom, window.location, untyped hooks. Use when setting up TanStack Router or file-based routing.

First seen May 20, 2026

Installation

$ npx skills add redpanda-data/ui-harness --skill setup-tanstack-router

Stronger alternatives

This repository is archived — consider an actively maintained alternative.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from redpanda-data/ui-harness · top by installs.

npx skills add redpanda-data/ui-harness

Browse all from redpanda-data/ui-harness

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 34
License LICENSE
Default branch main
Open issues 0
Status Archived

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 3,464 B
  • docs SUMMARY.md 234 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 2 installs

SKILL.md

TanStack Router Enforcement

What This Catches

  • Ban react-router-dom imports
  • Ban window.location navigation (block) + reads (warn)
  • Warn window.location.reload() -- suggest router.invalidate()
  • Ban strict: false in router hooks
  • Ban untyped useParams()/useSearch()/useLoaderData()/useRouteContext() missing { from }
  • Ban URLSearchParams -- suggest nuqs
  • Warn exported components from route files (break code splitting)
  • Require validateSearch when useSearch in route files
  • Warn when Query-primed loaders are consumed via useLoaderData instead of useQuery/useSuspenseQuery
  • Warn when router uses queryClient context without defaultPreloadStaleTime: 0
  • Warn when router uses queryClient context without createRootRouteWithContext

Auto-regen route tree on route file change.

TanStack Router + Query

When a route needs server data, prefer this ownership split:

  • Router loader: start fetching early after navigation intent.
  • TanStack Query: own cache, refetch, invalidation, and garbage collection.
  • Component: read via useQuery() or useSuspenseQuery() so Query has an active observer.

Do not enforce suspense globally. Choose per field/page:

  • useSuspenseQuery() for blocking, page-critical data that should use route pending/error boundaries.
  • useQuery() for deferred or secondary data with inline loading/empty/error states.
export const Route = createFileRoute('/dashboards/$dashboardId')({
  loader: ({ context, params }) => {
    context.queryClient.prefetchQuery(dashboardQueryOptions(params.dashboardId))
  },
  component: Dashboard,
})

function Dashboard() {
  const params = Route.useParams()
  const dashboard = useSuspenseQuery(dashboardQueryOptions(params.dashboardId))
  const widgetCount = useQuery(widgetCountQueryOptions(params.dashboardId))

  return <DashboardView dashboard={dashboard.data} widgetCount={widgetCount.data} />
}

Router setup when Query owns cache:

const rootRoute = createRootRouteWithContext<{ queryClient: QueryClient }>()({
  component: RootLayout,
})

const router = createRouter({
  routeTree,
  context: { queryClient },
  defaultPreloadStaleTime: 0,
  defaultPendingComponent: DefaultLoader,
  defaultErrorComponent: DefaultError,
})

Avoid Route.useLoaderData() for Query-loaded data. It bypasses Query observers, so focus refetch, invalidation refetch, and cache retention can behave surprisingly.

Customization

Routes dir pattern default /routes/. Update grep pattern in hook scripts if project use different convention:

if ! echo "$file_path" | grep -qE '/routes/'; then    # default
if ! echo "$file_path" | grep -qE '/pages/'; then     # pages-based
if ! echo "$file_path" | grep -qE '/app/routes/'; then # nested

Type-Safe Search Params with nuqs

import { useQueryState, parseAsInteger, parseAsString } from 'nuqs'

function UsersPage() {
  const [page, setPage] = useQueryState('page', parseAsInteger.withDefault(1))
  const [filter, setFilter] = useQueryState('filter', parseAsString)
}

Setup (install, config, verify): see [SETUP.md](SETUP.md).