Web Browser
Launch the built-in web browser with bidirectional messaging
nx.js can launch the Nintendo Switch's built-in web browser as a Library Applet, with support for bidirectional messaging between your app and the browser via window.nx.
Web browser applets require Application mode. Your app must be running as an installed NSP, or launched from hbmenu while holding over a game (title override).
Firmware 19.0.0+: Web browser applets currently do not work on firmware version 19 and later when using Atmosphère. This is a limitation of Atmosphère's compatibility with the web applet on newer firmware — not a nx.js issue. If you need web applet functionality, stay on firmware 18.x or earlier until Atmosphère adds support.
Online Mode
Pass an HTTP or HTTPS URL to open a web page in the browser. The nx.js event loop continues running, so your app can send and receive messages while the browser is open.
const applet = new Switch.WebApplet('https://example.com');
applet.addEventListener('message', (e) => {
console.log('From browser:', e.data);
applet.sendMessage('Hello from nx.js!');
});
applet.addEventListener('exit', () => {
console.log('Browser closed');
});
await applet.start({ jsExtension: true });
console.log(applet.mode); // "web-session"The browser page can communicate back using the window.nx API:
// In the browser page
window.nx.addEventListener('message', (evt) => {
console.log('From nx.js:', evt.data);
});
window.nx.sendMessage('Hello from the browser!');The window.nx API is only available when jsExtension is set to true in the start() options.
HtmlDoc Mode
The htmldoc mode loads HTML directly from the app's HtmlDocument NCA — no network connection required. This is ideal for bundling a HTML-based UI with your app.
const applet = new Switch.WebApplet('htmldoc:/index.html');
applet.addEventListener('message', (e) => {
const msg = JSON.parse(e.data);
const response = { id: msg.id, result: 'ok' };
applet.sendMessage(JSON.stringify(response));
});
await applet.start({ jsExtension: true });
console.log(applet.mode); // "htmldoc"Setting Up Offline HTML
Create an htmldoc directory in your app root with your HTML files:
When building your NSP with @nx.js/nsp, the htmldoc/ contents are automatically wrapped into the required NCA structure and included in the NSP.
Configuration
All configuration is passed as an options object to start(). Options control display, input, and media behavior of the browser applet. Every option is optional with sensible defaults.
await applet.start({
jsExtension: true,
footer: false,
leftStickMode: 'pointer',
bootDisplayKind: 'black',
pageScrollIndicator: false,
});For the full list of available options, see the WebAppletOptions API reference.
RPC Pattern
A common pattern is to use JSON-based RPC between your app and the browser UI:
// nx.js side
const applet = new Switch.WebApplet('htmldoc:/index.html');
applet.addEventListener('message', (e) => {
const msg = JSON.parse(e.data);
let result;
switch (msg.type) {
case 'readDir':
result = Switch.readDirSync(msg.path);
break;
case 'readFile':
result = new TextDecoder().decode(
Switch.readFileSync(msg.path)
);
break;
}
applet.sendMessage(JSON.stringify({
id: msg.id,
data: result,
}));
});
await applet.start({ jsExtension: true });// Browser side
let msgId = 0;
const pending = {};
function rpc(type, data) {
const id = ++msgId;
return new Promise((resolve) => {
pending[id] = resolve;
window.nx.sendMessage(JSON.stringify({ id, type, ...data }));
});
}
window.nx.addEventListener('message', (evt) => {
const msg = JSON.parse(evt.data);
if (msg.id && pending[msg.id]) {
pending[msg.id](msg.data);
delete pending[msg.id];
}
});
// Usage
const files = await rpc('readDir', { path: 'sdmc:/' });