Vix.cpp v2.8.5 is here Read the blog
Skip to content

App shell ​

Vix UI provides app shell primitives for running server-rendered Vix interfaces inside desktop or WebView-style containers.

The app shell does not replace the web application.

It wraps a normal Vix web UI and opens it as an application window.

cpp
#include <vix/ui/shell/AppShell.hpp>
#include <vix/ui/shell/ShellConfig.hpp>

Or use the UI umbrella header:

cpp
#include <vix/ui.hpp>

When to use it ​

Use the app shell when you already have a Vix web page, dashboard, admin panel, internal tool, or mobile-ready UI and you want to run it like an app.

Typical use cases:

  • desktop dashboards
  • internal tools
  • admin panels
  • local-first tools
  • server-rendered interfaces
  • WebView-based desktop apps
  • UI examples opened from a local Vix server

The important idea is simple:

txt
Vix server-rendered UI -> local HTTP server -> app shell window

Basic shell configuration ​

ShellConfig describes the app window and the target URL.

cpp
vix::ui::ShellConfig config = vix::ui::ShellConfig::make()
                                  .set_name("Vix Desktop App")
                                  .set_title("Vix Desktop Shell")
                                  .set_host("127.0.0.1")
                                  .set_port(8080)
                                  .set_width(1200)
                                  .set_height(800)
                                  .set_resizable(true)
                                  .set_fullscreen(false)
                                  .set_devtools(true);

The effective URL is built from the host and port:

cpp
std::cout << config.effective_url() << "\n";

Output:

txt
http://127.0.0.1:8080

Start a shell ​

cpp
#include <iostream>

#include <vix/ui.hpp>

int main()
{
  vix::ui::ShellConfig config = vix::ui::ShellConfig::make()
                                    .set_name("Vix Desktop App")
                                    .set_title("Vix Desktop Shell")
                                    .set_host("127.0.0.1")
                                    .set_port(8080)
                                    .set_width(1200)
                                    .set_height(800)
                                    .set_resizable(true)
                                    .set_fullscreen(false)
                                    .set_devtools(true)
                                    .set_start_server(false);

  vix::ui::AppShell shell = vix::ui::AppShell::make(config);

  const vix::ui::Result<void> result = shell.start();

  if (result.is_failed())
  {
    std::cerr << "failed to start desktop shell: "
              << result.error_message()
              << "\n";

    return 1;
  }

  std::cout << "desktop shell started\n";
  std::cout << "target url: " << shell.target_url() << "\n";
  std::cout << "status: " << shell.status() << "\n";

  return 0;
}

Run it:

bash
vix run main.cpp

This example expects the target server to already be running at:

txt
http://127.0.0.1:8080

Managed server mode ​

The app shell can also start a local server command before opening the window.

Use managed server mode when the shell should control the server process.

cpp
#include <iostream>
#include <string>

#include <vix/ui.hpp>

int main()
{
  const std::string command =
      "vix run ui_dashboard.cpp --force-server --run --port 8080";

  vix::ui::ShellConfig config = vix::ui::ShellConfig::make()
                                    .set_name("Vix UI Server App")
                                    .set_title("Vix UI Desktop Shell")
                                    .set_host("127.0.0.1")
                                    .set_port(8080)
                                    .set_width(1200)
                                    .set_height(800)
                                    .set_resizable(true)
                                    .set_fullscreen(false)
                                    .set_devtools(true)
                                    .set_start_server(true)
                                    .set_server_command(command);

  vix::ui::AppShell shell = vix::ui::AppShell::make(config);

  const vix::ui::Result<void> result = shell.start();

  if (result.is_failed())
  {
    std::cerr << "failed to start desktop shell: "
              << result.error_message()
              << "\n";

    return 1;
  }

  return 0;
}

In this mode, the app shell starts the server command and then opens the configured target URL.

Readiness check ​

For better startup behavior, the shell can wait until the server is ready.

cpp
#include <chrono>
#include <iostream>
#include <string>

#include <vix/ui.hpp>

int main()
{
  const std::string command =
      "vix run ui_dashboard.cpp --force-server --run --port 8080";

  vix::ui::ShellConfig config = vix::ui::ShellConfig::make()
                                    .set_name("Vix UI Readiness App")
                                    .set_title("Vix UI Desktop Readiness")
                                    .set_app_id("com.vix.ui.readiness")
                                    .set_app_version("0.8.0")
                                    .set_vendor("Vix.cpp")
                                    .set_host("127.0.0.1")
                                    .set_port(8080)
                                    .set_readiness_url("http://127.0.0.1:8080/health")
                                    .set_startup_timeout(std::chrono::milliseconds(5000))
                                    .set_wait_for_server(true)
                                    .set_start_server(true)
                                    .set_server_command(command)
                                    .set_width(1200)
                                    .set_height(800)
                                    .set_resizable(true)
                                    .set_devtools(true);

  vix::ui::AppShell shell = vix::ui::AppShell::make(config);

  std::cout << "starting local server:\n";
  std::cout << "  " << command << "\n";
  std::cout << "waiting for readiness URL:\n";
  std::cout << "  " << config.effective_readiness_url() << "\n";
  std::cout << "opening target URL:\n";
  std::cout << "  " << shell.target_url() << "\n";

  const vix::ui::Result<void> result = shell.start();

  if (result.is_failed())
  {
    std::cerr << "failed to start desktop shell: "
              << result.error_message()
              << "\n";

    return 1;
  }

  std::cout << "desktop shell closed\n";
  std::cout << "status: " << shell.status() << "\n";

  return 0;
}

This avoids opening the shell before the server is ready.

Using environment variables ​

For examples and local tools, the server command can come from an environment variable.

cpp
#include <cstdlib>
#include <iostream>
#include <string>

#include <vix/ui.hpp>

static std::string env_or_empty(const char *name)
{
  const char *value = std::getenv(name);

  if (value == nullptr)
  {
    return {};
  }

  return std::string(value);
}

int main()
{
  const std::string command = env_or_empty("VIX_UI_SERVER_CMD");

  if (command.empty())
  {
    std::cerr << "missing server command\n";
    std::cerr << "usage:\n";
    std::cerr << "  VIX_UI_SERVER_CMD=\"<server command>\" ./app\n";
    return 1;
  }

  vix::ui::ShellConfig config = vix::ui::ShellConfig::make()
                                    .set_name("Vix UI Server App")
                                    .set_title("Vix UI Desktop Shell")
                                    .set_host("127.0.0.1")
                                    .set_port(8080)
                                    .set_width(1200)
                                    .set_height(800)
                                    .set_resizable(true)
                                    .set_fullscreen(false)
                                    .set_devtools(true)
                                    .set_start_server(true)
                                    .set_server_command(command);

  vix::ui::AppShell shell = vix::ui::AppShell::make(config);

  const vix::ui::Result<void> result = shell.start();

  if (result.is_failed())
  {
    std::cerr << result.error_message() << "\n";
    return 1;
  }

  return 0;
}

Run it:

bash
VIX_UI_SERVER_CMD="vix run ui_dashboard.cpp --force-server --run --port 8080" \
vix run main.cpp

Desktop command ​

The easiest way to run a Vix UI file as a desktop app is through the desktop command.

bash
vix desktop run ui_dashboard.cpp --port 8080

Example output:

txt
info  Building desktop server:
• /home/softadastra/tmp/ui/ui_dashboard.cpp

Vix Desktop
app        Vix Desktop
target     http://127.0.0.1:8080
mode       dev (managed server)

Vix.cpp   READY   v2.7.0   run
> HTTP:    http://localhost:8080/
- Status:  ready
- Hint:    Ctrl+C to stop the server

This command builds the C++ UI server, starts it, and opens it through the desktop shell flow.

Example Vix UI server ​

A shell usually opens a normal Vix server-rendered page.

cpp
#include <vix/core.hpp>
#include <vix/ui.hpp>

int main()
{
  vix::App app;

  app.templates("templates");

  app.get("/", [](vix::Request &req, vix::Response &res) {
    (void)req;

    const std::string flash =
        vix::ui::FlashMessage::success("Vix UI dashboard is running.")
            .set_title("Ready")
            .set_dismissible(true)
            .render();

    auto view =
        vix::ui::View("dashboard.html")
            .set_title("Vix UI Dashboard")
            .set("flash", flash)
            .set("framework", "Vix.cpp")
            .set("module", "vix::ui");

    res.ui(view);
  });

  app.run(8080);
  return 0;
}

Run it as a desktop app:

bash
vix desktop run ui_dashboard.cpp --port 8080

ShellConfig reference ​

Common configuration methods:

MethodPurpose
set_name(...)Internal app name
set_title(...)Window title
set_app_id(...)App identifier
set_app_version(...)App version
set_vendor(...)Vendor name
set_icon_path(...)App icon path
set_url(...)Explicit target URL
set_host(...)Target host
set_port(...)Target port
set_readiness_url(...)URL used to check readiness
set_startup_timeout(...)Maximum readiness wait time
set_wait_for_server(...)Wait before opening the shell
set_start_server(...)Start a server command
set_server_command(...)Command used to start the server
set_width(...)Window width
set_height(...)Window height
set_resizable(...)Allow resizing
set_fullscreen(...)Start fullscreen
set_devtools(...)Enable developer tools

Effective URL ​

When no explicit URL is set, the shell builds the target URL from host and port.

cpp
vix::ui::ShellConfig config;

config.set_host("127.0.0.1")
      .set_port(8080);

std::cout << config.effective_url() << "\n";

Output:

txt
http://127.0.0.1:8080

Use set_url(...) when you want full control:

cpp
config.set_url("http://127.0.0.1:8080/admin");

Effective readiness URL ​

If a readiness URL is provided, the shell uses it.

cpp
config.set_readiness_url("http://127.0.0.1:8080/health");

If no readiness URL is provided, the shell can fall back to the effective target URL.

cpp
std::cout << config.effective_readiness_url() << "\n";

ServerProcess ​

ServerProcess is a small helper for starting and stopping a local server process.

cpp
vix::ui::ServerProcess process("sleep 30");

vix::ui::Result<void> start = process.start();

if (start.is_ok())
{
  std::cout << "server pid: " << process.pid() << "\n";
}

process.stop();

It is used by the app shell when managed server mode is enabled.

Most users do not need to use it directly unless they are building custom shell workflows.

ServerReadiness ​

ServerReadiness checks whether a server endpoint is reachable.

cpp
auto endpoint =
    vix::ui::ServerReadiness::parse_url("http://127.0.0.1:8080/health");

if (endpoint.is_failed())
{
  std::cerr << endpoint.error_message() << "\n";
  return 1;
}

auto ready = vix::ui::ServerReadiness::check_once(endpoint.value());

if (ready.is_ok())
{
  std::cout << "server is ready\n";
}

Wait for a server:

cpp
auto result =
    vix::ui::ServerReadiness::wait(
        "http://127.0.0.1:8080/health",
        std::chrono::milliseconds(5000));

if (result.is_failed())
{
  std::cerr << result.error_message() << "\n";
}

Result handling ​

App shell operations return vix::ui::Result<void>.

Always check the result before assuming the shell started correctly.

cpp
const vix::ui::Result<void> result = shell.start();

if (result.is_failed())
{
  std::cerr << result.error_message() << "\n";
  return 1;
}

Common workflows ​

Open an existing local server ​

Start your server first:

bash
vix run ui_dashboard.cpp --force-server --run --port 8080

Then open a shell that targets:

txt
http://127.0.0.1:8080

Let the shell start the server ​

Use:

cpp
config.set_start_server(true)
      .set_server_command("vix run ui_dashboard.cpp --force-server --run --port 8080");

Wait until the server is ready ​

Use:

cpp
config.set_wait_for_server(true)
      .set_readiness_url("http://127.0.0.1:8080/health")
      .set_startup_timeout(std::chrono::milliseconds(5000));

Use the desktop command ​

bash
vix desktop run ui_dashboard.cpp --port 8080

This is the simplest workflow for Vix UI desktop examples.

Common mistakes ​

Opening the shell before the server is ready ​

If the page is blank or fails to load, enable readiness waiting.

cpp
config.set_wait_for_server(true)
      .set_readiness_url("http://127.0.0.1:8080/health");

Forgetting to start the server ​

If set_start_server(false) is used, the app shell only opens the target URL.

It does not start the Vix server.

cpp
config.set_start_server(false);

Use this only when the server is already running.

Using the wrong port ​

The shell port and the server port must match.

cpp
config.set_port(8080);

Run the server on the same port:

bash
vix desktop run ui_dashboard.cpp --port 8080

Missing health route ​

If the readiness URL is /health, the server should expose it.

cpp
app.get("/health", [](vix::Request &, vix::Response &res) {
  res.json({"ok", true});
});

Treating app shell as a native widget toolkit ​

The app shell is not a native UI toolkit.

It is designed to open web-first Vix UI applications inside an app window.

For UI rendering, use normal Vix routes, templates, HTML responses, forms, assets, live fragments, and PWA helpers.

What to remember ​

AppShell opens a configured URL as an application shell.

ShellConfig describes the app name, window, URL, server command, and readiness behavior.

ServerProcess can start and stop a local server.

ServerReadiness can wait until the server is reachable.

txt
ShellConfig -> AppShell -> target URL
                      -> optional server process
                      -> optional readiness check

For normal usage, prefer:

bash
vix desktop run ui_dashboard.cpp --port 8080

Next step ​

Continue with UI examples.

Open the examples guide

Released under the MIT License.