🚧 VeloxKit is pre-release software. APIs may change before v1.0. Get started →
Documentation
Guides
Routing

Routing Stable

VeloxKit ships with @velox/router — a named-route history-stack router built for native desktop apps. It uses the same mental model as React Navigation: a stack of { name, params } entries with no URLs.

Desktop apps have no URL bar, so file-based URL routing is not a good fit. @velox/router uses named routes — fast, simple, and works offline.

Install

npm install @velox/router

Setup

Declare routes with <Route> components inside <Router>:

import { Router, Route } from '@velox/router'
import HomeScreen from './screens/HomeScreen'
import DetailScreen from './screens/DetailScreen'
import SettingsScreen from './screens/SettingsScreen'
 
export default function App() {
  return (
    <Router initialRoute="home">
      <Route name="home"     component={HomeScreen} />
      <Route name="detail"   component={DetailScreen} />
      <Route name="settings" component={SettingsScreen} />
    </Router>
  )
}

initialRoute sets the first screen. If omitted, the first declared <Route> is used.

Navigating between screens

import { useNavigate } from '@velox/router'
 
function HomeScreen() {
  const navigate = useNavigate()
 
  return (
    <Pressable onPress={() => navigate('detail', { id: 42 })}>
      <Text>Open detail</Text>
    </Pressable>
  )
}

navigate(name, params?, opts?):

CallEffect
navigate('detail', { id: 42 })Push detail screen with params
navigate('back')Pop current screen (back)
navigate('home', {}, { replace: true })Replace current screen

Reading route params

import { useRoute } from '@velox/router'
 
function DetailScreen() {
  const { name, params, canGoBack } = useRoute()
 
  return (
    <View style={{ flex: 1, padding: 24 }}>
      <Text>Route: {name}</Text>
      <Text>ID: {params.id}</Text>
    </View>
  )
}

useRoute() returns:

FieldTypeDescription
namestring | nullCurrent route name
paramsobjectParams passed to navigate()
canGoBackbooleantrue when history stack has more than one entry

Back button

import { useNavigate, useRoute } from '@velox/router'
import { Pressable, Text } from 'veloxkit'
 
function BackButton() {
  const navigate = useNavigate()
  const { canGoBack } = useRoute()
 
  if (!canGoBack) return null
 
  return (
    <Pressable onPress={() => navigate('back')}>
      <Text>← Back</Text>
    </Pressable>
  )
}

Active route highlighting

import { useRoute, useNavigate } from '@velox/router'
 
function NavItem({ route, label }: { route: string; label: string }) {
  const { name } = useRoute()
  const navigate = useNavigate()
  const isActive = name === route
 
  return (
    <Pressable onPress={() => navigate(route)}>
      <Text style={{ color: isActive ? '#00A878' : '#A0A0B2' }}>{label}</Text>
    </Pressable>
  )
}

Sidebar layout with router

A common pattern for desktop apps — persistent sidebar navigation alongside a routed content area:

import { Router, Route, useNavigate, useRoute } from '@velox/router'
import { View, Text, Pressable } from 'veloxkit'
 
function SidebarItem({ route, label }: { route: string; label: string }) {
  const { name } = useRoute()
  const navigate = useNavigate()
 
  return (
    <Pressable
      onPress={() => navigate(route)}
      style={{
        paddingVertical: 10,
        paddingHorizontal: 16,
        backgroundColor: name === route ? '#00A87820' : 'transparent',
        borderRadius: 6,
      }}
    >
      <Text style={{ color: name === route ? '#00A878' : '#ccc' }}>{label}</Text>
    </Pressable>
  )
}
 
function Layout() {
  return (
    <View style={{ flex: 1, flexDirection: 'row' }}>
      {/* Sidebar */}
      <View style={{ width: 200, backgroundColor: '#1a1a24', padding: 12 }}>
        <SidebarItem route="home"     label="Home" />
        <SidebarItem route="notes"    label="Notes" />
        <SidebarItem route="settings" label="Settings" />
      </View>
 
      {/* Content — Router renders the active screen here */}
      <View style={{ flex: 1 }}>
        <Router initialRoute="home">
          <Route name="home"     component={HomeScreen} />
          <Route name="notes"    component={NotesScreen} />
          <Route name="settings" component={SettingsScreen} />
        </Router>
      </View>
    </View>
  )
}

TypeScript

Type your params with a route map:

type Routes = {
  home: {}
  detail: { id: number }
  settings: {}
}

Then narrow params in screens:

function DetailScreen() {
  const { params } = useRoute()
  const { id } = params as Routes['detail']
  // ...
}

Full API

ExportDescription
<Router initialRoute?>Router container. Renders the active screen.
<Route name component>Route declaration. Always renders null itself.
useNavigate()Returns navigate(name, params?, opts?)
useRoute()Returns { name, params, canGoBack }