@bobfrankston/msger
v0.1.186
Published
Fast, lightweight, cross-platform message box - Rust-powered alternative to msgview
Downloads
11,037
Maintainers
Readme
@bobfrankston/msger
Fast, lightweight message boxes for Node.js applications.
Display native message boxes, dialogs, and HTML content with a simple JavaScript API. Works on Windows, Linux (x64), and Linux (ARM64/Raspberry Pi).
Quick Links
- Installation - Get started
- Command Line Usage - Use from shell scripts
- Node.js API - Use from JavaScript/TypeScript
- For Developers - Building & architecture
- Roadmap - Technical status & planned features
Installation
npm install @bobfrankston/msgerFor global CLI usage:
npm install -g @bobfrankston/msgerSupported Platforms:
- Windows (x64)
- Linux (x64)
- Linux (ARM64 / Raspberry Pi)
Command Line Usage
The msger command-line tool provides a quick way to display message boxes from shell scripts, batch files, or terminal.
Basic Examples
# Simple message
msger -message "Hello, World!"
msger Hello World # shorthand - words become message
# With HTML content
msger -html "<h1>Welcome!</h1><p>This is <strong>HTML</strong></p>"
# Colored text with inline styles
msger -html "<span style='color:red;background-color:yellow'>Alert!</span>"
# Load a URL (web page or local file)
msger -url "https://example.com"
msger -url "file:///path/to/page.html"
# Load URL with hash fragment
msger -url "https://example.com" -hash section1
msger -url "https://example.com" -hash "#intro"
# With input field and placeholder
msger -message "Enter your name:" -input "Your name here" -default "John"
# Custom buttons
msger -message "Save changes?" -buttons Yes No Cancel
# With custom size and position
msger -message "Hello" -size 800,600 -pos 100,100
# Always on top with zoom
msger -message "Important!" -ontop -zoom 150
# Detached URL browser (stays open after script exits)
msger -url "https://example.com" -detach
# Fullscreen mode
msger -fullscreen -url "https://example.com"
# Multi-monitor (Windows only - show on second screen)
msger -message "Second screen" -pos 0,100 -screen 1
# Auto-close timeout
msger -message "Closing in 5 seconds..." -timeout 5
# Open with DevTools for debugging (automatically opens DevTools panel)
msger -url "https://example.com" -dev
# See all options
msger --helpJSON Configuration Files
You can store message box configuration in a JSON file for reuse. JSON files support comments (JSON5 format).
# Load configuration from file
msger -load config.json
# Override specific values from loaded config
msger -load config.json -title "New Title" -size 800,600
# Save current command-line options to a file (only saves explicitly specified values)
msger -title "My Dialog" -message "Hello" -buttons Yes No -save my-config.json
# Save config without showing the message box (uses -noshow)
msger -title "My Dialog" -message "Hello" -buttons Yes No -save my-config -noshow
# Load base config, override, and save the overrides
msger -load base.json -title "Modified" -save modified.json
# Save and show (saves config then displays the message box)
msger -title "Test" -message "Saving config..." -save test.jsonNotes:
- The
-saveoption saves only the explicitly specified command-line arguments, not derived defaults. This keeps config files minimal and allows defaults to evolve. - Use
-noshowwith-saveto create config files without displaying the message box. - File extensions: If you don't specify
.json, it will be added automatically (e.g.,myconfigbecomesmyconfig.json).
Complete JSON Structure
{
"title": "Window Title",
"message": "Plain text message (supports ANSI color codes)",
"html": "<h1>HTML content</h1><p>Rich formatting</p>",
"url": "https://example.com",
"hash": "section1",
"size": {
"width": 600,
"height": 400
},
"pos": {
"x": 100,
"y": 100,
"screen": 0
},
"buttons": ["Cancel", "OK"],
"defaultValue": "default input text",
"inputPlaceholder": "Enter text here...",
"allowInput": false,
"timeout": 30,
"autoSize": false,
"alwaysOnTop": false,
"fullscreen": false,
"zoom": 100,
"debug": false,
"icon": "path/to/icon.png",
"dev": false
}Field Reference
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| title | string | "Message" | Window title |
| message | string | null | Plain text message (supports ANSI color codes) |
| html | string | null | HTML content to display |
| url | string | null | URL to load (web or file://) |
| hash | string | null | Hash fragment to append to URL (requires url). Leading # is optional. |
| size | object | {"width": 600, "height": 400} | Window size |
| size.width | number | 600 (or 1024 for URLs) | Window width in pixels |
| size.height | number | 400 (or 768 for URLs) | Window height in pixels |
| pos | object | null | Window position |
| pos.x | number | - | X coordinate in pixels |
| pos.y | number | - | Y coordinate in pixels |
| pos.screen | number | null | [Windows only] Screen index (0=primary, 1=second, etc.) |
| buttons | string[] | ["OK"] | Button labels |
| defaultValue | string | null | Default input value |
| inputPlaceholder | string | null | Placeholder text for input field |
| allowInput | boolean | false | Show input field |
| timeout | number | null | Auto-close after N seconds |
| autoSize | boolean | true when no size | Auto-resize window to fit content |
| alwaysOnTop | boolean | false | Keep window on top |
| fullscreen | boolean | false | Start in fullscreen mode |
| zoom | number | 100 | Initial zoom level (100=100%, 150=150%) |
| debug | boolean | false | Return debug info in result |
| icon | string | null | Path to window icon (.png, .ico) |
| dev | boolean | false | Open DevTools automatically (for debugging HTML/URL content) |
Content Priority: Only one content type will be displayed (in order):
url- If provided, loads URL (ignores message/html)html- If provided, displays HTML (ignores message)message- Plain text with ANSI color support
Backward Compatibility: The old width and height fields (at the top level) are still supported for backward compatibility, but the size object is preferred. If both are provided, size takes precedence.
JSON Examples
Simple dialog:
{
"title": "Confirm",
"message": "Are you sure?",
"buttons": ["Cancel", "OK"]
}Input dialog:
{
"title": "Enter Name",
"message": "Please enter your name:",
"allowInput": true,
"inputPlaceholder": "Your name here",
"defaultValue": "John Doe",
"buttons": ["Cancel", "Submit"]
}HTML content:
{
"title": "Welcome",
"html": "<h1>Welcome!</h1><p>Getting started...</p>",
"size": {
"width": 700,
"height": 500
}
}Positioned window on second monitor:
{
"message": "Second screen",
"pos": {
"x": 0,
"y": 100,
"screen": 1
}
}CLI Options Reference
Usage: msger [options] [message words...]
Options:
-message, --message <text> Plain text message
-title, --title <text> Window title
-html, --html <html> HTML content
-url, --url <url> URL to load (web or file://)
-hash, --hash <fragment> Hash fragment to append to URL (requires -url). Leading # optional.
-buttons, --buttons <labels> Button labels (e.g., -buttons Yes No Cancel)
-ok, --ok Add OK button
-cancel, --cancel Add Cancel button
-input, --input [placeholder] Include input field with optional placeholder text
-default, --default <text> Default value for input field
-size, --size <width,height> Window size (e.g., -size 800,600)
-pos, --pos <x,y> Window position (e.g., -pos 100,200)
-screen, --screen <number> [Windows only] Screen index (0=primary, 1=second, etc.)
-zoom, --zoom <percent> Zoom level as percentage (e.g., -zoom 150 for 150%)
-timeout, --timeout <seconds> Auto-close after specified seconds
-ontop, --ontop Keep window always on top
-detach, --detach Launch window independently (parent returns immediately)
-fullscreen, --fullscreen Start window in fullscreen mode (F11 to toggle, Escape to exit)
-debug, --debug Return debug info (HTML, size, autoSize) in result
-v, -version, --version Show version number
-help, -?, --help Show help message
Keyboard Shortcuts:
- Enter: Click default (last) button
- Escape: Dismiss dialog or exit fullscreen
- F11: Toggle fullscreen mode
- F12: Open developer tools (DevTools/Inspect)
- Ctrl+Wheel/Plus/Minus: Zoom in/out
- Ctrl+0: Reset zoom to 100%
Debug Mode:
- Set environment variable MSGER_DEBUG=1 for diagnostic output
- Shows: startup info, keyboard events, IPC messages, button clicks
- Example (PowerShell): $env:MSGER_DEBUG=1; msger "Test"
- Zero performance impact when disabled
Notes:
- If no options provided, all non-option arguments are concatenated as message
- Press ESC to dismiss (returns button: "dismissed")
- Press Enter to click last (default) button
- OK button is green by default
- URLs default to 1024x768 window size
- Window title automatically updates from loaded page's <title> tag when using -url
- Windows auto-size to fit content when size not specified
- Runtime zoom: Ctrl+Wheel, Ctrl+Plus, Ctrl+MinusNode.js API Reference
Use msger in your Node.js or TypeScript applications with a simple Promise-based API.
Quick Start
import { showMessageBox } from '@bobfrankston/msger';
const result = await showMessageBox({
title: 'Confirm Action',
message: 'Are you sure you want to proceed?',
buttons: ['Cancel', 'OK']
});
console.log('User clicked:', result.button);
if (result.value) {
console.log('User entered:', result.value);
}Programmatic Close API (New!)
Close message boxes programmatically from the parent process:
Handle-based API (Recommended):
import { showMessageBoxEx } from '@bobfrankston/msger';
const handle = showMessageBoxEx({
message: 'Processing...',
buttons: ['Cancel']
});
console.log('Dialog PID:', handle.pid);
// Close after 5 seconds
setTimeout(() => {
handle.close();
}, 5000);
// Wait for result
const result = await handle.result;
// Result: {button: 'closed', closed: true} if closed programmatically
// Result: {button: 'Cancel'} if user clicked CancelStandalone close function:
import { showMessageBoxEx, closeMessageBox } from '@bobfrankston/msger';
const handle = showMessageBoxEx({ message: 'Working...' });
const pid = handle.pid;
// Close by PID from anywhere
closeMessageBox(pid);Use cases:
- Progress dialogs that auto-close when task completes
- Timeout-based notifications
- Managing multiple dialogs by PID
- Detached dialogs closed remotely
See CLOSE-API.md for complete documentation.
API Functions
showMessageBox(options: MessageBoxOptions): Promise<MessageBoxResult>
Display a message box dialog and wait for user response.
MessageBoxOptions
interface MessageBoxOptions {
title?: string; // Window title (default: "Message")
message?: string; // Plain text message (optional if url or html provided)
html?: string; // HTML content to display
url?: string; // URL to load (web URL or file:// path)
hash?: string; // Hash fragment to append to URL (requires url). Leading # optional.
size?: { // Window size in pixels
width: number; // Window width (default: 600, or 1024 for URLs)
height: number; // Window height (default: 400, or 768 for URLs)
};
pos?: { // Window position
x: number; // X coordinate in pixels
y: number; // Y coordinate in pixels
screen?: number; // [Windows only] Screen index (0=primary, 1=second, etc.)
};
buttons?: string[]; // Button labels (default: ["OK"])
defaultValue?: string; // Default input value
inputPlaceholder?: string; // Placeholder text (gray hint) for input field
allowInput?: boolean; // Show input field (default: false)
autoSize?: boolean; // Auto-resize window to fit content (default: true when no size specified)
alwaysOnTop?: boolean; // Keep window on top of other windows (default: false)
zoom?: number; // Initial zoom level (100=100%, 150=150%, 50=50%)
timeout?: number; // Auto-close after N seconds
detach?: boolean; // Launch detached from parent process
fullscreen?: boolean; // Start window in fullscreen mode (F11 to toggle)
debug?: boolean; // Return debug info (HTML, size, autoSize) in result
}MessageBoxResult
interface MessageBoxResult {
button: string; // Label of clicked button
value?: string; // Input value (if allowInput was true)
form?: object; // Form data (if form elements present)
closed?: boolean; // True if closed programmatically via handle.close()
dismissed?: boolean; // True if user pressed Escape
timeout?: boolean; // True if closed due to timeout
debug?: { // Debug info (if debug option was true)
html: string; // Generated HTML content
width: number; // Window width
height: number; // Window height
autoSize: boolean; // Whether auto-sizing is enabled
};
}API Examples
Simple Confirmation Dialog
const result = await showMessageBox({
title: 'Delete File',
message: 'Are you sure you want to delete this file?',
buttons: ['Cancel', 'Delete']
});
if (result.button === 'Delete') {
// Perform deletion
}Input Dialog
const result = await showMessageBox({
title: 'Enter Name',
message: 'Please enter your name:',
allowInput: true,
inputPlaceholder: 'Your name here',
defaultValue: 'John Doe',
buttons: ['Cancel', 'OK']
});
if (result.button === 'OK') {
console.log('Name entered:', result.value);
}HTML Content
const result = await showMessageBox({
title: 'Welcome',
html: `
<div style="font-family: sans-serif;">
<h2 style="color: #2563eb;">Welcome!</h2>
<p>This supports <strong>HTML</strong> content.</p>
<ul>
<li>Rich formatting</li>
<li>Custom styles</li>
<li>Any HTML elements</li>
</ul>
</div>
`,
size: { width: 700, height: 500 },
buttons: ['Close']
});ANSI Color Codes
Plain text messages automatically support ANSI color escape sequences, which are converted to HTML with proper colors:
const result = await showMessageBox({
title: 'Color Test',
message: '\x1b[31mRed text\x1b[0m\n\x1b[32mGreen text\x1b[0m\n\x1b[1m\x1b[34mBold blue\x1b[0m',
buttons: ['OK']
});Supported ANSI codes:
- Colors: Red (31), Green (32), Yellow (33), Blue (34), Magenta (35), Cyan (36), White (37)
- Styles: Bold (1), Underline (4), Reset (0)
- Backgrounds: 40-47 (same color numbers as foreground)
CLI example:
echo -e "\x1b[31mError:\x1b[0m Something went wrong" | msgerDisplay a Web Page
// Load external website
// Note: Window title automatically updates from page's <title> tag
await showMessageBox({
url: 'https://github.com/BobFrankston/msger',
size: { width: 1024, height: 768 }
});
// Load local HTML file
await showMessageBox({
url: 'file:///path/to/help.html',
size: { width: 800, height: 600 }
});
// Load with DevTools opened automatically (for debugging)
await showMessageBox({
url: 'https://example.com',
dev: true, // Opens DevTools automatically
size: { width: 1024, height: 768 }
});Auto-Close with Timeout
// Show notification that auto-closes after 3 seconds
// A translucent countdown indicator appears in the top-right corner
const result = await showMessageBox({
title: 'Notification',
message: 'File saved successfully!',
timeout: 3,
buttons: ['OK']
});
if (result.timeout) {
console.log('Notification auto-closed');
}The countdown timer displays as a subtle yellow badge in the top-right corner, showing the remaining seconds (e.g., "10s", "9s", "8s"...).
HTML Forms
const result = await showMessageBox({
title: 'User Registration',
html: `
<form>
<label>Name: <input name="name" required /></label><br>
<label>Email: <input name="email" type="email" required /></label><br>
<label>Age: <input name="age" type="number" /></label>
</form>
`,
buttons: ['Cancel', 'Submit']
});
if (result.button === 'Submit' && result.form) {
console.log('Name:', result.form.name);
console.log('Email:', result.form.email);
console.log('Age:', result.form.age);
}Window Positioning
// Position at specific coordinates
await showMessageBox({
message: 'Positioned window',
pos: { x: 100, y: 100 }
});
// Position on second monitor (Windows only)
await showMessageBox({
message: 'On second screen',
pos: { x: 0, y: 100, screen: 1 }
});Always On Top & Zoom
// Keep window on top with 150% zoom
await showMessageBox({
title: 'Important Alert',
message: 'This window stays on top!',
alwaysOnTop: true,
zoom: 150
});Auto-Sizing Window
// Window automatically sizes to fit content
await showMessageBox({
message: 'Short message',
autoSize: true // default when size not specified
});Detached URL Browser
// Launch URL window that stays open after script exits
await showMessageBox({
url: 'https://example.com',
size: { width: 1200, height: 800 },
detach: true,
alwaysOnTop: true
});
// Script continues/exits immediately, window stays openFullscreen Mode
// Launch window in fullscreen mode (like F11 in browser)
await showMessageBox({
url: 'https://example.com',
fullscreen: true
});
// Users can press F11 to toggle fullscreen or Escape to exit
// Fullscreen with message
await showMessageBox({
message: 'Full screen presentation',
fullscreen: true,
buttons: ['Close']
});Features
- ✅ Display plain text, HTML content, or load URLs
- ✅ Full HTML/CSS support
- ✅ ANSI color codes (colored terminal output)
- ✅ Customizable buttons
- ✅ Input fields and forms
- ✅ Auto-close with timeout
- ✅ Window positioning and sizing
- ✅ Multi-monitor support (Windows)
- ✅ Always on top mode
- ✅ Zoom control
- ✅ Fullscreen mode
- ✅ TypeScript type definitions
- ✅ Keyboard shortcuts (Enter, Escape, F11, F12)
Why msger?
- Fast - Opens in under 200ms
- Small - Only a few MB installed
- Simple - Easy Promise-based API
- Flexible - Plain text, HTML, or load URLs
- Cross-platform - Works on Windows and Linux
For technical details and performance metrics, see DEVELOPERS.md.
msger vs msgview
This package is the Rust/wry-based implementation. There's also @bobfrankston/msgview - an Electron-based alternative with the same API.
| Aspect | msger (this) | msgview | |--------|--------------|---------| | Startup | ~50-200ms | ~2-3 seconds | | Size | ~5-10MB | ~200MB | | Technology | Rust + wry (WebView2/webkit2gtk) | Electron | | Pi/Linux | ❌ Rendering issues | ✅ Perfect | | Windows/WSL | ✅ Works | ✅ Works |
When to use msger (this package)
- Speed is critical (CLI tools, automation)
- Small binary size matters
- Windows or WSL environment
When to use msgview
- Running on Raspberry Pi or Linux
- Need reliable cross-platform rendering
- Prefer Electron ecosystem
Planned: msgapi
Both packages will share a common JavaScript API (window.msgapi) for file system access, window manipulation, and bidirectional communication. See TODO.md for details.
For the complete feature comparison and roadmap, see the shared TODO.md which tracks both projects.
Additional Information
Important Notes
Taskbar Icons
Icon Behavior Differences:
- Window Title Bar: Shows custom icon from
-iconflag or JSON config - Windows Taskbar: Shows the embedded msger.exe icon (cannot be changed at runtime)
This is a Windows limitation for native applications. The taskbar icon comes from the executable's embedded resource, not the runtime window icon. In contrast, Electron-based msgview can set taskbar icons dynamically.
Workaround: The planned -pin feature with AppUserModelID will allow each pinned shortcut to have its own taskbar icon.
Security
⚠️ msger is designed for displaying trusted, friendly content (local apps, your HTML files). It is NOT a secure sandbox for untrusted/hostile web content. Use -htmlfrom and -url with trusted sources only.
msger JavaScript API
Minimal API - Most functionality uses native browser APIs:
msger.isAvailable()- Feature detection (returns true in msger)msger.close()- Same aswindow.close()(native API preferred)
Recommendation: Use native browser APIs (localStorage, window.close()) for compatibility. Code will work in any browser context, not just msger.
For Developers
- Building & Architecture: See DEVELOPERS.md
- Technical Status & Roadmap: See TODO.md
- Native Binary Documentation: See msger-native/README.md
License
ISC
Author
Bob Frankston
