App

The main application class for Nib menu bar applications. App manages the entire lifecycle of a Nib application, including window configuration, view rendering, event handling, system integration, and communication with the Swift runtime.

Constructor

nib.App(title=None, icon=None, identifier=None)

Parameters

Parameter Type Default Description
title str | None None Text displayed in the menu bar next to the icon
icon str | SFSymbol | View | None None Menu bar icon. An SF Symbol name, an SFSymbol instance, or any View
identifier str | None None Bundle identifier, used as the UserDefaults domain. Defaults to com.nib.<slug of the title>; a built app uses its bundle identifier.

Properties

Window and Appearance

Property Type Description
title str Text displayed in the menu bar. Readable and writable
icon str | SFSymbol | View Menu bar icon. An SF Symbol name, an SFSymbol instance, or any View. A view is rendered at the menu bar height of 22 points, width from its fitting size, and updates when its properties change
identifier str Bundle identifier and UserDefaults domain. Derived from the title (com.nib.<slug>) unless set; inside a built app it is the bundle identifier.
width float Popover window width in points
height float Popover window height in points
float_on_top bool Keep the popover open on outside clicks. When True it closes only from code or by clicking the status bar icon again. Default False
show_quit_item bool When True, appends a styled "Quit" button at the bottom of the app UI
Property Type Description
menu list[MenuItem] Right-click context menu items for the status bar icon
fonts dict[str, str] Custom fonts registered for the app. Maps font names to file paths or URLs. Fonts placed in assets/fonts/ are auto-detected

Lifecycle Callbacks

Property Type Description
on_appear Callable[[], None] Called every time the popover opens
on_disappear Callable[[], None] Called every time the popover closes
on_quit Callable[[], None] Called once when the app quits and, under nib run, when a reload replaces the app
on_sleep Callable[[], None] Called when the Mac is about to sleep
on_wake Callable[[], None] Called when the Mac wakes
on_screen_lock Callable[[], None] Called when the screen locks
on_screen_unlock Callable[[], None] Called when the screen unlocks
on_appearance_change Callable[[bool], None] Called with dark when the system switches between light and dark
on_displays_change Callable[[], None] Called when a display is connected, removed or rearranged
is_running bool Read-only. False once the app has quit or been replaced by a reload; background threads should check it

Settings

Property Type Description
settings SettingsPage Settings page configuration. When set, the preferences window is accessible via Cmd+,
clipboard str Write-only setter for clipboard content. Use get_clipboard() for reading

Service Properties (read-only)

Property Type Description
notifications NotificationManager Push, schedule, and manage macOS notifications
battery Battery Read battery level and charging state
connectivity Connectivity Check network connectivity status
screen Screen Get display info and control brightness
keychain Keychain Secure storage for passwords and tokens
camera Camera List devices, capture photos, access video frames
launch_at_login LaunchAtLogin Control whether the app starts on login
permissions Permissions Check and request Camera, Microphone, and Notification permissions

Methods

View Management

build(view)

Set the root view of the application. If the app is already running, triggers an immediate re-render.

app.build(view: View) -> None
Parameter Type Description
view View The root view to display in the popover

body()

Override this method in a subclass to define the UI. Returns the root view. Only used in the class-based approach.

app.body() -> View

update()

Manually trigger a UI re-render. Use this to force an update when the automatic reactivity system might not detect a change, or to batch multiple changes into a single render pass.

app.update() -> None

Application Lifecycle

run()

Start the application. Connects to the Swift runtime, performs the initial render, and enters the main event loop. Blocks until the app quits.

app.run() -> None

quit()

Quit the application and clean up resources.

app.quit() -> None

Notifications

notify(title, body, subtitle, sound, identifier)

Send a macOS system notification.

app.notify(
    title: str,
    body: str | None = None,
    subtitle: str | None = None,
    sound: bool = True,
    identifier: str | None = None,
) -> None
Parameter Type Default Description
title str none Notification title (required)
body str | None None Notification body text
subtitle str | None None Subtitle shown below the title
sound bool True Play the default notification sound
identifier str | None None Unique ID for updating or removing the notification later

Clipboard

get_clipboard(callback)

Read clipboard content asynchronously. The callback receives the clipboard string.

app.get_clipboard(callback: Callable[[str], None]) -> None

set_clipboard(content)

Set clipboard content. Equivalent to app.clipboard = content.

app.set_clipboard(content: str) -> None

Hotkeys

on_hotkey(shortcut, callback)

Register a global keyboard shortcut.

app.on_hotkey(shortcut: str, callback: Callable[[], None]) -> None
Parameter Type Description
shortcut str Key combination, e.g. "cmd+shift+n", "cmd+k"
callback Callable Function called when the hotkey is pressed

hotkey(shortcut)

Decorator form of on_hotkey.

@app.hotkey("cmd+shift+n")
def show_window():
    pass

System Events

event(name)

Decorator form of the on_<event> lifecycle properties, the way hotkey is for on_hotkey. Assigning the property and using the decorator do the same thing; each event holds one callback.

@app.event("wake")
def refresh():
    pass

@app.event("appearance")
def themed(dark: bool):
    pass
Name Property
appear, disappear on_appear, on_disappear
sleep, wake on_sleep, on_wake
screen_lock, screen_unlock on_screen_lock, on_screen_unlock
appearance on_appearance_change
displays on_displays_change

An unknown name raises ValueError. Callbacks run on the event thread like actions; an exception is logged and never stops the app. See the System Events guide.

Settings

register_settings(settings)

Register a Settings object for persistence. Connects the settings to UserDefaults and waits for initial values to load.

app.register_settings(settings: Settings) -> None

open_settings()

Open the settings window programmatically.

app.open_settings() -> None

close_settings()

Close the settings window programmatically.

app.close_settings() -> None

Class Methods

set_assets_dir(path)

Set the assets directory for the application. Relative paths are resolved from the main script directory.

App.set_assets_dir(path: str | Path | None) -> None

resolve_asset(relative_path)

Resolve a relative asset path to an absolute path. Returns the input unchanged for absolute paths and URLs. Returns an empty string if the asset is not found.

App.resolve_asset(relative_path: str) -> str

Examples

import nib

def main(app: nib.App):
    app.title = "Counter"
    app.icon = nib.SFSymbol("number.circle")
    app.width = 280
    app.height = 150

    label = nib.Text("0", font=nib.Font.TITLE)

    def increment():
        label.content = str(int(label.content) + 1)

    app.build(
        nib.VStack(
            controls=[
                label,
                nib.Button("Increment", action=increment),
            ],
            spacing=12,
            padding=20,
        )
    )

nib.run(main)

Class-based app

import nib

class CounterApp(nib.App):
    count = nib.State(0)

    def body(self):
        return nib.VStack(
            controls=[
                nib.Text(f"Count: {self.count}", font=nib.Font.TITLE),
                nib.Button("Increment", action=self.increment),
            ],
            spacing=12,
            padding=20,
        )

    def increment(self):
        self.count += 1

CounterApp(title="Counter", icon="number.circle").run()

View as the menu bar icon

Any view works as the icon, and it stays reactive. Full demo: examples/features/custom_icon.py.

import random
import nib

def main(app: nib.App):
    chart = nib.Chart(
        data=[{"x": i, "y": v} for i, v in enumerate([4, 6, 12, 14, 10, 8, 11, 9])],
        marks=[nib.LineMark(x="x", y="y", foreground_style="#ffffff", line_width=1.0)],
        x_axis=nib.ChartAxis(hidden=True),
        y_axis=nib.ChartAxis(hidden=True),
        legend=nib.ChartLegend(hidden=True),
        width=30,
        height=16,
    )
    app.icon = chart

    def randomize():
        chart.data = [{"x": i, "y": random.randint(4, 16)} for i in range(8)]

    app.build(nib.Button("Randomize", action=randomize, padding=20))

nib.run(main)