Back

Switch React Menu

A Minimalist Home Menu for Nintendo Switch - December 2024

  • Navigate
  • QE Page (L / R)
  • EnterZ Select (A)
  • X Back (B)

Role

  • Mobile Development
  • UI + UX Design

Team

  • Solo

Timeline

  • Started: Dec 2024
  • Expanded: May–Jun 2026

Overview

A minimalist home menu for Nintendo Switch

This Nintendo Switch App Launcher is a minimalist implementation of a traditional home menu. It relies on the JavaScript library nx.js, built by TooTallNate, to render React components to a generic canvas element through the react-tela library.

While the react-tela framework itself is runtime-agnostic, it was the only way I could find to run the JSX runtime on the Nintendo Switch. Even though this interface relies on minimal reactivity, I thought the concept of running a React app on a console was interesting enough to be worth exploring.

Low-Level Control The framework gave me shockingly low-level access to the hardware. Through the Canvas API, I was able to draw pixels and shapes directly to the screen instead of interacting with a Document Object Model (DOM), like in traditional JavaScript.

TypeScript Support Coming from a Java background, I'm a big fan of what TypeScript brings to JavaScript. Adding type safety to code is a common sense addition to any language, and it's become so ingrained in my workflow that I can't really live without it.

React Tooling React's declarative UI feels like a natural fit for a quick and dirty app like this. Reacting to state changes felt far more natural to work with than manually updating the UI, especially when it came to handling controller input.

92 total commits
4 total bursts of freeform work
1 UI shared between the Nintendo Switch and browser

(as of June 2026)

Context

The React I remember, but without strings attached

In the Winter of 2024, I found myself with a full break from school for the holidays and a lot of time to kill. It made sense to start working on something new that I could show off, while also keeping the scope small enough that I could realistically finish the thing by the end of the break.

I had already been pretty invested in the world of Nintendo homebrew by this point. I had custom firmware running on not just my switch, but pretty much every Nintendo console I owned (Wii, DSI, 3DS, and Wii U). So I really liked the idea of taking a stab at building an app for a Nintendo console. However, I found the typical options to be a little lacking. Working with C/C++ seemed like it would be too much of a pain to get started, and I didn't want to spend too much time tinkering with the low-level details of the console's APIs in order to build a simple app.

While JavaScript may not be an obvious choice, it's actually relatively fast compared to other high level options like Python, and its frontend ecosystem plays well with UI development. Ultimately, nx.js ended up being amazing for those reasons.

Project timeline

Four bursts across 92 commits

This timeline groups the four biggest sprints of the project with the features that were shipped in each.

  1. December 2024 26 commits

    First build

    A launcher over the holiday break

    What I built. The initial base of the project that pulls from the Switch's app catalog to draw icons to the screen and launch apps via A-press. It displays a row of apps in pages, using the L and R shoulder buttons to skip between pages.

    skeleton nxjs baseapp launching functionalityshoulder buttons paginationselections via dpadautomate font bundling
    Why it mattered Controller-based browsing and app launching

    Without the basic rendering loop and app launching functionality, there would be no project to build upon.

  2. May 2026 21 commits

    Off-console iteration

    Move iteration off the console

    What I built. This sprint focused on implementing the Vite pipeline, allowing for the React component tree to be fully device-agnostic and render in the browser. It also added a set of comprehensive settings to mutate the UI's appearance and behavior.

    implement vite pipeline with browser previewimplement pagination dotsimplement last played trackingimplement compact viewimplement custom sort mode
    Why it mattered Testing without Switch hardware

    Testing in the browser proved to be a huge time saving measure, as I could patch the UI in real-time without having to build and deploy to the console every time I wanted to test a change.

  3. May 2026 40 commits

    Growing the surface

    Turn a launcher into a navigable home surface

    What I built. This turned the launcher from a basic interface with Switch home menu feature parity into a fully-featured home surface with search, tags, and a photo album. This iteration used a local database compiled at build metadata for each game to display metadata for each game in a rich detail view.

    implement showing page #s featureadd album pageimplement web appletimplement cached loads with manual invalidationimplement game tagging with badge displayadd search bar functionalityimplement tag autocomplete in search
    Why it mattered Providing context and aesthetic appeal

    This iteration allowed the project to differentiate itself from the original menu and give it functionality more akin to a PlayStation home menu. The gradients and colors were a nice touch, and the rich detail panel was a nice touch to add some visual flair to the project without adding too much technical overhead.

  4. June 2026 4 commits

    Cleanup

    Stabilize on console hardware

    What I built. This sprint focused on cleaning up documentation, squashing bugs, and migrating the static database to dynamic RAWG fetching. By this time, I had worked out how to use fetch and a simple proxy to get game metadata without having to deal with a pre-generated database.

    Expand README.mdreplace mockup img referenced in READMEprune legacy igdb database (commit reports 64% smaller bundle)fix virtual-keyboard lifecycle crash after RAWG loading
    Why it mattered 15.2 MB catalog removed; measured romfs ≈91% smaller

    Migrating the database to dynamic fetching massively reduces the bundle size and allows the project to include future titles that may not have been available at the time of the initial build.

Development

One interface pipeline, two execution environments

The development process was a bit of a rollercoaster. I started out by trying to use the Canvas API directly, but it was a bit of a pain to work with. I ended up using the react-tela library to render the React components to a canvas, which was a lot easier to work with.

The same React tree that runs on Switch is available in the interactive browser preview at the top of this page. Game metadata is fetched through a server-side RAWG proxy, so the API key never ships to the browser.

00 - React The React Framework

The React framework was the foundation of this project. It allowed for me to declare how I wanted the UI to look, without having much regard for what platform it was built for. This platform agnostic approach allowed me to focus on the core features I wanted to build, without worrying about the nitty gritty details.

01 - react-tela src/main.tsx

This version of React allows the project to adapt its UI to paint to the Switch's screen through the Canvas2D API, taking full advantage of the Switch’s rendering pipeline and performance characteristics.

02 - React-DOM src/browser/main.tsx

The browser uses polyfilling to emulate Switch-like functionality, mapping gamepad inputs to the keyboard and mouse inputs to touch. The browser view renders in a scaled 1280 x 720 window to match the Switch's aspect ratio.

Catalog and layout I also had to become familiar with the Switch.Application API. It reads the switch's app titles, authors, and box art from the Switch's app catalog. Each image renders exactly 40 pixels away from each other so that the grid can fit exactly 4 apps across the Switch's 1280 pixel width screen.

Input and selection chrome Controller inputs are handled by a custom hook that listens for button presses and updates the UI accordingly. It listens for both left and right directional inputs on the stick and D-pad, as well as detecting shoulder buttons to quickly swap pages. It also listens for the A button to launch whatever app is selected.

Final Build

What the project supports today

The project leads with a modular presentation, giving the user options to switch between different views. Users can display their games in a row, a grid, or a list. They can also search for games by title, genre, or tag. While the rich details panel is the highlighted feature, it can be freely disabled if the user prefers a more minimal approach.

Grid + compact list

Controller, touch, and shoulder-button navigation

Search + tags

Full-text filtering, tag chips, and autocomplete

Metadata cache + editing

Offline resume, refresh, and per-title overrides

Settings + sorting

Recent, alphabetical, release, launch count, and custom order

Photo album

Grid browsing, lightbox navigation, and delete confirmation

Web shortcut

System browser handoff through the Switch's native web browser shortcut

Browser preview

Vite, nx.js port, keyboard gamepad, and mouse touch

Nintendo Switch mockup showing the completed rich-details interface

The rich-details view allows users to see more information about the given game they're playing, courtesy of RAWG.

01

Keyboard as gamepad

QEEnter

Rehearse console navigation in the browser preview. By mapping keyboard keys to gamepad controls in the browser, developers can simulate authentic console navigation without having to touch bare-metal hardware.

02

Searching and sorting

#tagX

Full-text filtering, tag chips, and autocomplete, with a custom sort mode in the settings. The search bar allows users to filter down games based on key characteristics like title, genre, and tag.

03

Progressive game detail

AEdit

Access game metadata right from the menu itself. The rich detail panel gives the menu some color, while giving users more information about the game(s) they're playing.