npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@smart-tv/ui

v1.3.3

Published

A comprehensive React component library tailored for Smart TV applications. It provides spatial navigation, focusable UI components, routing, and utilities for building fast, accessible TV experiences with remote control or keyboard navigation.

Readme

@smart-tv/ui

A comprehensive React component library tailored for Smart TV applications. It provides spatial navigation, focusable UI components, routing, and utilities for building fast, accessible TV experiences with remote control or keyboard navigation.

Features

  • 🎯 Spatial Navigation - Smart directional navigation with customizable focus management
  • 🎨 UI Components - Pre-built focusable components (Button, Card, Menu, Navbar, Sidebar)
  • 🧭 Routing System - Built-in router with navigation stack management
  • 📱 On-Screen Keyboard - Virtual keyboard with multiple layouts and themes
  • 🎭 Overlay Components - Dialog, Drawer, Snackbar, Tooltip
  • 📐 Layout System - Grid and Row components for responsive layouts
  • 🔧 React Hooks - useFocusable, useFocusContext, useRouter, and more
  • 🐛 Visual Debugger - Visual feedback for focus states during development
  • Accessibility - Built with TV accessibility standards in mind

Installation

Install the package using your preferred package manager:

# npm
npm install @smart-tv/ui

# pnpm
pnpm add @smart-tv/ui

# yarn
yarn add @smart-tv/ui

Import Styles

Don't forget to import the CSS file in your app:

import "@smart-tv/ui/styles.css";

Quick Start

Basic Setup

Wrap your app with the required providers. AppProvider is mandatory and must be the outermost provider:

import { AppProvider, RouterProvider, Route, Button } from "@smart-tv/ui";
import "@smart-tv/ui/styles.css";

function App() {
  return (
    <AppProvider
      init={{
        debug: false,
        visualDebug: false,
        distanceCalculationMethod: "center",
      }}
    >
      <RouterProvider>
        <Route path="/" component={HomePage} />
        <Route path="/details/:id" component={DetailsPage} />
      </RouterProvider>
    </AppProvider>
  );
}

export default App;

With Query Client (for data fetching)

If you're using @smart-tv/query for data management:

import { QueryClient, QueryClientProvider } from "@smart-tv/query";
import { AppProvider, RouterProvider, Route } from "@smart-tv/ui";
import "@smart-tv/ui/styles.css";

const queryClient = new QueryClient({
  staleTime: 1000 * 60 * 5, // 5 minutes
  cacheTime: 1000 * 60 * 10, // 10 minutes
});

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <AppProvider
        init={{
          debug: false,
          visualDebug: false,
        }}
      >
        <RouterProvider>
          <Route path="/" component={HomePage} />
        </RouterProvider>
      </AppProvider>
    </QueryClientProvider>
  );
}

export default App;

Core Providers

AppProvider (Required)

The main provider that initializes the spatial navigation system. This provider is mandatory for the library to work.

import { AppProvider } from "@smart-tv/ui";

<AppProvider
  init={{
    debug: false, // Enable debug logging
    visualDebug: false, // Show visual focus indicators
    nativeMode: false, // Use native focus behavior
    throttle: 0, // Throttle navigation in milliseconds
    shouldFocusDOMNode: true, // Focus actual DOM nodes
    rtl: false, // Right-to-left support
    distanceCalculationMethod: "center", // 'center' | 'edges' | 'corners'
  }}
>
  {/* Your app */}
</AppProvider>;

RouterProvider (Recommended)

Built-in routing system with navigation stack management:

import { RouterProvider, Route, Link, useRouter } from "@smart-tv/ui";

<RouterProvider initial="/" maxStack={50}>
  <Route path="/" component={HomePage} />
  <Route path="/movies" component={MoviesPage} />
  <Route path="/movie/:id" component={MovieDetails} />
</RouterProvider>;

Router hooks:

  • useRouter() - Access navigation methods (push, back, replace)
  • useParams() - Get route parameters
  • useLocation() - Get current route state

QueryClientProvider (Optional)

For data fetching and caching (from @smart-tv/query):

import { QueryClient, QueryClientProvider } from '@smart-tv/query'

const queryClient = new QueryClient({
  staleTime: 1000 * 60 * 5,
  cacheTime: 1000 * 60 * 10,
})

<QueryClientProvider client={queryClient}>
  {/* Your app */}
</QueryClientProvider>

Components

Core Components

Screen

Main screen wrapper component:

import { Screen } from "@smart-tv/ui";

<Screen id="home" title="Home">
  {/* Screen content */}
</Screen>;

Section

Focusable section within a screen:

import { Section } from "@smart-tv/ui";

<Section focusKey="hero-section">{/* Section content */}</Section>;

UI Components

Button

import { Button } from "@smart-tv/ui";

<Button onPress={() => console.log("Pressed")} variant="primary">
  Play Now
</Button>;

Card

import { Card } from "@smart-tv/ui";

<Card focusKey="card-1" onPress={() => navigate("/details/1")}>
  <img src="poster.jpg" alt="Movie" />
  <h3>Movie Title</h3>
</Card>;

Menu & Navbar

import { Menu, Navbar } from "@smart-tv/ui";

<Navbar>
  <Menu items={menuItems} />
</Navbar>;

Sidebar

import { Sidebar } from "@smart-tv/ui";

<Sidebar position="left" width={250}>
  {/* Sidebar content */}
</Sidebar>;

Layout Components

Grid

import { Grid } from "@smart-tv/ui";

<Grid columns={4} gap={16}>
  {items.map((item) => (
    <Card key={item.id} {...item} />
  ))}
</Grid>;

Row

import { Row } from "@smart-tv/ui";

<Row gap={12} align="center">
  {/* Row items */}
</Row>;

Overlay Components

Dialog

import { Dialog } from "@smart-tv/ui";

<Dialog open={isOpen} onClose={() => setIsOpen(false)}>
  <h2>Confirm Action</h2>
  <p>Are you sure?</p>
  <Button onPress={handleConfirm}>Yes</Button>
</Dialog>;

Drawer

import { Drawer } from "@smart-tv/ui";

<Drawer open={isOpen} position="right">
  {/* Drawer content */}
</Drawer>;

Snackbar

import { Snackbar } from "@smart-tv/ui";

<Snackbar message="Action completed" duration={3000} />;

Tooltip

import { Tooltip } from "@smart-tv/ui";

<Tooltip content="More information">
  <Button>Help</Button>
</Tooltip>;

Search Components

Keyboard (On-Screen Keyboard)

import { Keyboard } from "@smart-tv/ui";

<Keyboard
  value={searchQuery}
  onChange={setSearchQuery}
  onSubmit={handleSearch}
  layout="qwerty" // 'qwerty' | 'abc' | 'numeric'
  theme="dark"
/>;

Hooks

useFocusable

Register a component as focusable:

import { useFocusable } from "@smart-tv/ui";

function CustomComponent() {
  const { ref, focused } = useFocusable({
    focusKey: "my-component",
    onEnterPress: () => console.log("Enter pressed"),
    onArrowPress: (direction) => console.log(direction),
    onFocus: () => console.log("Focused"),
    onBlur: () => console.log("Blurred"),
  });

  return (
    <div ref={ref} className={focused ? "focused" : ""}>
      {/* Component content */}
    </div>
  );
}

useFocusContext

Access focus context in nested components:

import { useFocusContext } from "@smart-tv/ui";

function NestedComponent() {
  const { focusKey, focused } = useFocusContext();
  return <div>Focus Key: {focusKey}</div>;
}

useRouter

Navigate between routes:

import { useRouter } from "@smart-tv/ui";

function MovieCard() {
  const router = useRouter();

  const handlePress = () => {
    router.push("/movie/123", { from: "home" });
  };

  return <Button onPress={handlePress}>View Details</Button>;
}

useParams

Access route parameters:

import { useParams } from "@smart-tv/ui";

function MovieDetails() {
  const { id } = useParams();
  return <div>Movie ID: {id}</div>;
}

Utilities

measureLayout

Measure component dimensions:

import { measureLayout } from "@smart-tv/ui";

const layout = measureLayout(element);
// { left, top, right, bottom, width, height, x, y }

VisualDebugger

Enable visual debugging during development:

import { VisualDebugger } from "@smart-tv/ui";

// Enable in AppProvider
<AppProvider init={{ visualDebug: true }}>{/* Your app */}</AppProvider>;

WritingDirection

Support for RTL layouts:

import { WritingDirection } from "@smart-tv/ui";

// Enable RTL
<AppProvider init={{ rtl: true }}>{/* Your app */}</AppProvider>;

Complete Example

Here's a complete example showing all the main providers working together:

import { QueryClient, QueryClientProvider } from "@smart-tv/query";
import {
  AppProvider,
  RouterProvider,
  Route,
  Screen,
  Grid,
  Card,
} from "@smart-tv/ui";
import "@smart-tv/ui/styles.css";

const queryClient = new QueryClient({
  staleTime: 1000 * 60 * 5,
  cacheTime: 1000 * 60 * 10,
});

function HomePage() {
  const movies = [
    { id: 1, title: "Movie 1", poster: "/poster1.jpg" },
    { id: 2, title: "Movie 2", poster: "/poster2.jpg" },
  ];

  return (
    <Screen id="home" title="Home">
      <Grid columns={4} gap={20}>
        {movies.map((movie) => (
          <Card
            key={movie.id}
            focusKey={`movie-${movie.id}`}
            onPress={() => router.push(`/movie/${movie.id}`)}
          >
            <img src={movie.poster} alt={movie.title} />
            <h3>{movie.title}</h3>
          </Card>
        ))}
      </Grid>
    </Screen>
  );
}

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <AppProvider
        init={{
          debug: false,
          visualDebug: false,
          distanceCalculationMethod: "center",
        }}
      >
        <RouterProvider>
          <Route path="/" component={HomePage} />
          <Route path="/movie/:id" component={MovieDetails} />
        </RouterProvider>
      </AppProvider>
    </QueryClientProvider>
  );
}

export default App;

Key Navigation

The library automatically handles these keys:

  • Arrow Keys (↑ ↓ ← →): Navigate between focusable elements
  • Enter: Activate focused element (trigger onPress/onEnterPress)
  • Back/Escape: Go back in navigation stack

You can customize key mappings in the AppProvider configuration.

Documentation

For comprehensive documentation, API references, and interactive examples, visit:

📚 https://smart-tv-docs.vercel.app/components/ui

The documentation includes:

  • Complete component API references
  • Interactive examples and demos
  • Best practices for Smart TV development
  • Migration guides and troubleshooting

Package Structure

@smart-tv/ui/
├── core/          # Core providers (AppProvider, RouterProvider, Screen, Section)
├── components/    # UI components (Button, Card, Menu, Navbar, Sidebar)
├── layout/        # Layout components (Grid, Row)
├── overlay/       # Overlay components (Dialog, Drawer, Snackbar, Tooltip)
├── search/        # Search components (Keyboard)
├── hooks/         # React hooks (useFocusable, useFocusContext, useRouter)
└── utils/         # Utilities (measureLayout, VisualDebugger, WritingDirection)

You can import from specific subpaths:

import { AppProvider } from "@smart-tv/ui/core";
import { Button, Card } from "@smart-tv/ui/components";
import { Grid } from "@smart-tv/ui/layout";
import { Dialog } from "@smart-tv/ui/overlay";
import { useFocusable } from "@smart-tv/ui/hooks";

Development

Building the package

From the monorepo root:

# Install dependencies
pnpm install

# Build all packages
pnpm build

# Build only @smart-tv/ui
pnpm --filter=@smart-tv/ui build

Running the demo app

# Start the demo app
pnpm --filter=demo dev

Watching for changes

# Watch and rebuild on changes
pnpm --filter=@smart-tv/ui dev:bundle
pnpm --filter=@smart-tv/ui dev:styles

Debugging Tips

  1. Enable Visual Debug Mode:

    <AppProvider init={{ visualDebug: true }}>

    This will show focus boundaries around focusable elements.

  2. Enable Debug Logging:

    <AppProvider init={{ debug: true }}>

    This will log navigation events to the console.

  3. Check Focus Key: Every focusable component should have a unique focusKey prop for proper navigation.

  4. Navigation not working?

    • Ensure AppProvider is wrapping your entire app
    • Check that components have the focusKey prop
    • Verify that components are actually rendered (check with React DevTools)

Browser Support

  • Chrome/Edge 90+
  • Firefox 88+
  • Safari 14+
  • Smart TV browsers (Tizen, webOS, etc.)

TypeScript Support

The library is written in TypeScript and includes full type definitions. No additional @types packages are needed.

import type {
  InitOptions,
  Direction,
  FocusableComponentLayout,
} from "@smart-tv/ui";

Contributing

We welcome contributions! Please follow these guidelines:

  1. Code Style: Follow the existing code style and use ESLint
  2. Testing: Add tests for new features
  3. Documentation: Update the README and docs for API changes
  4. Commits: Use conventional commit messages

See CONTRIBUTING.md for more details.

License

BSD 3-Clause License - see LICENSE for details.

Related Packages

Support


Made with ❤️ for Smart TV developers