Router
Client-side routing system with history management, dynamic routes, and focus-aware navigation for Smart TV apps.
Import
import {
RouterProvider,
Route,
Link,
useRouter,
useParams,
useRoute,
useLocation
} from '@smart-tv/ui';
Basic Usage
import { AppProvider, RouterProvider, Route, Screen } from '@smart-tv/ui';
function HomeScreen() {
return (
<Screen focusKey="home" selFocus>
<h1>Home Screen</h1>
</Screen>
);
}
function AboutScreen() {
return (
<Screen focusKey="about" selFocus>
<h1>About Screen</h1>
</Screen>
);
}
function App() {
return (
<AppProvider>
<RouterProvider initial="/">
<Route path="/" component={HomeScreen} />
<Route path="/about" component={AboutScreen} />
</RouterProvider>
</AppProvider>
);
}
Dynamic Routes with Parameters
Use :param
syntax for dynamic route segments.
import { useParams } from '@smart-tv/ui';
function PlayerScreen() {
const { id } = useParams<{ id: string }>();
return (
<Screen focusKey="player" selFocus>
<h1>Playing video: {id}</h1>
</Screen>
);
}
function App() {
return (
<AppProvider>
<RouterProvider initial="/">
<Route path="/" component={HomeScreen} />
<Route path="/player/:id" component={PlayerScreen} />
<Route path="/category/:categoryId/video/:videoId" component={DetailScreen} />
</RouterProvider>
</AppProvider>
);
}
Navigation with Link Component
import { Link, Button } from '@smart-tv/ui';
function HomeScreen() {
return (
<Screen focusKey="home">
<h1>Home</h1>
{/* Link as a focusable button */}
<Link to="/about" focusKey="about-link">
<Button>Go to About</Button>
</Link>
{/* Link with parameters */}
<Link to="/player/123" focusKey="player-link">
<Button>Watch Video 123</Button>
</Link>
{/* Link with state */}
<Link
to="/details"
state={{ videoData: { title: 'My Video' } }}
focusKey="details-link"
>
<Button>View Details</Button>
</Link>
</Screen>
);
}
Programmatic Navigation
Use the useRouter
hook for programmatic navigation.
import { useRouter, Button } from '@smart-tv/ui';
function HomeScreen() {
const router = useRouter();
const handleNavigate = () => {
// Navigate to a route
router.push('/about');
// Navigate with parameters
router.push('/player/456');
// Navigate with state
router.push('/details', { videoId: '789' });
// Go back
router.back();
// Replace current route (no history entry)
router.replace('/login');
// Check if can go back
if (router.canGoBack()) {
router.back();
}
};
return (
<Screen focusKey="home">
<Button focusKey="nav-button" onEnterPress={handleNavigate}>
Navigate
</Button>
</Screen>
);
}
Router Configuration
Configure router behavior with advanced options.
<RouterProvider
initial="/"
maxStack={10} // Limit history stack size
collapseSameBase={true} // Collapse routes with same base path
skipDuplicates={true} // Skip duplicate consecutive routes
>
<Route path="/" component={HomeScreen} />
<Route path="/about" component={AboutScreen} />
</RouterProvider>
Skippable Routes
Mark routes as skippable to bypass them when navigating back.
<RouterProvider initial="/">
<Route path="/" component={HomeScreen} />
{/* Loading screen will be skipped when going back */}
<Route path="/loading" component={LoadingScreen} skippable />
<Route path="/player/:id" component={PlayerScreen} />
</RouterProvider>
// When user goes from Home -> Loading -> Player
// and presses back, they'll return directly to Home, skipping Loading
useRoute Hook
Get current route information and state.
import { useRoute } from '@smart-tv/ui';
function MyScreen() {
const route = useRoute();
console.log(route.path); // Current path: "/player/123"
console.log(route.params); // Params: { id: "123" }
console.log(route.state); // Any state passed during navigation
console.log(route.skippable); // Whether route is skippable
return <div>Current path: {route.path}</div>;
}
useLocation Hook
Get current location information.
import { useLocation } from '@smart-tv/ui';
function Navigation() {
const location = useLocation();
return (
<nav>
<Link
to="/"
className={location.pathname === '/' ? 'active' : ''}
>
Home
</Link>
<Link
to="/about"
className={location.pathname === '/about' ? 'active' : ''}
>
About
</Link>
</nav>
);
}
Accessing Navigation State
// Passing state during navigation
function HomeScreen() {
const router = useRouter();
const openPlayer = (video) => {
router.push('/player/123', {
videoTitle: video.title,
resumeTime: video.lastPosition
});
};
return <Button onEnterPress={() => openPlayer(myVideo)}>Play</Button>;
}
// Receiving state in destination route
function PlayerScreen() {
const route = useRoute();
const { videoTitle, resumeTime } = route.state || {};
return (
<div>
<h1>{videoTitle}</h1>
<p>Resume from: {resumeTime}s</p>
</div>
);
}
RouterProvider Props
Prop | Type | Default | Description |
---|---|---|---|
initial | string | required | Initial route path |
maxStack | number | 50 | Max history stack size |
collapseSameBase | boolean | false | Collapse same base paths |
skipDuplicates | boolean | false | Skip duplicate routes |
Route Props
Prop | Type | Default | Description |
---|---|---|---|
path | string | required | Route path pattern |
component | ComponentType | required | Component to render |
skippable | boolean | false | Skip when navigating back |
useRouter Methods
Method | Signature | Description |
---|---|---|
push | (path, state?) => void | Navigate to path |
replace | (path, state?) => void | Replace current route |
back | () => void | Go back one route |
canGoBack | () => boolean | Check if can go back |
Best Practices
- Always wrap RouterProvider inside AppProvider
- Use dynamic parameters (:id) for content-specific routes
- Mark transient screens (loading, splash) as skippable
- Pass complex data via state instead of URL parameters
- Use replace() for redirects to avoid cluttering history
- Each Screen component should have selFocus for proper focus management
- Handle back button navigation with router.back() or browser back event