Skip to main content
The UI module is a single React component exported as the default export from src/ui/index.tsx. The shell renders it in the main content area when a pilot selects your plugin in the sidebar.

What the Shell Provides

The shell injects several libraries at runtime — you don’t need to bundle them, and the build system externalises them automatically. Import them directly:
  • react, react-dom
  • @tanstack/react-query, @tanstack/react-router
  • @skyvexsoftware/stratos-sdk (hooks, UI components, types, helpers)
  • sonner (toast notifications)
  • socket.io-client
  • maplibre-gl, react-map-gl/maplibre
Anything else you import — lucide-react, your own utilities, third-party libraries — will be bundled into your plugin’s ui/index.js.

Using usePluginContext()

The primary way to access shell state from any component in your plugin:
import { usePluginContext } from "@skyvexsoftware/stratos-sdk";

function MyComponent() {
  const ctx = usePluginContext();

  // ctx.pluginId       — your plugin's ID string
  // ctx.auth           — { isAuthenticated, token, user }
  // ctx.airline        — { id, name, icao, logo_light, logo_dark } or null
  // ctx.config         — { get<T>(key, default?) }
  // ctx.navigation     — navigate within/between plugins
  // ctx.toast          — { success(), error(), info(), warning() }
  // ctx.logger         — { info(), warn(), error(), debug() }
}
usePluginContext() can be called in any component in your tree — not just the root. The context is provided by the PluginShellProvider that wraps your entire plugin.

Auth

const { auth } = usePluginContext();

if (!auth.isAuthenticated) {
  return <p>Please log in to use this plugin.</p>;
}

// auth.user — the current pilot's profile object
// auth.token — the raw auth token (use sparingly)
You can also use the dedicated hook:
import { useShellAuth } from "@skyvexsoftware/stratos-sdk";

const { isAuthenticated, token, user } = useShellAuth();

Config

Read plugin settings declared in your manifest’s availableSettings. Config access in the UI module is synchronous — values are pre-loaded when your plugin mounts:
const { config } = usePluginContext();

const welcomeMsg = config.get<string>("welcome_message", "Hello!");
const showMap = config.get<boolean>("show_map", true);
const units = config.get<string>("units", "imperial");
The second argument to get() is the default value, returned when the setting has not been explicitly set. Navigate within your plugin or jump to other plugins and shell routes:
const { navigation } = usePluginContext();

// Within your plugin (appends to /plugins/my-plugin/)
navigation.navigateTo("roster");
navigation.navigateTo("roster/pilot-123");

// To another plugin
navigation.navigateToPlugin("flight-tracking", "history");

// To a shell page
navigation.navigateToShell("settings");

// Read the current path
const path = navigation.getCurrentPath();
For multi-page plugins, see the Routing page.

Toast Notifications

const { toast } = usePluginContext();

toast.success("Flight booked successfully");
toast.error("Failed to connect to VA server");
toast.info("New PIREP available");
toast.warning("Low fuel warning");
Or use the dedicated hook:
import { useShellToast } from "@skyvexsoftware/stratos-sdk";

const { success, error, info, warning } = useShellToast();

Styling

Plugins share the shell’s Tailwind CSS theme. Use standard Tailwind utility classes:
<div className="bg-card rounded-lg border p-6">
  <h2 className="text-lg font-semibold">Section Title</h2>
  <p className="text-muted-foreground mt-2 text-sm">Supporting text</p>
</div>
Key design tokens available via Tailwind classes:
ClassUsage
bg-cardCard and panel backgrounds
bg-mutedSubtle, secondary backgrounds
text-muted-foregroundSecondary and supporting text
borderStandard dividers and outlines
bg-primary / text-primaryAccent colour (configured per-airline)
bg-backgroundPage-level background
text-foregroundPrimary text
The shell switches between light and dark Tailwind themes automatically — your components inherit the correct variables without any additional work.

SDK UI Components

Import pre-built shadcn/ui components from the SDK to stay consistent with the shell’s design:
import {
  Button,
  Card,
  CardHeader,
  CardTitle,
  CardContent,
  Badge,
  Input,
  Label,
  Select,
  SelectTrigger,
  SelectValue,
  SelectContent,
  SelectItem,
  Tabs,
  TabsList,
  TabsTrigger,
  TabsContent,
  Dialog,
  DialogTrigger,
  DialogContent,
  DialogHeader,
  DialogTitle,
  Separator,
  Switch,
  Slider,
} from "@skyvexsoftware/stratos-sdk";
See UI Components for the full reference.

Minimal Example

import { usePluginContext, useShellAuth, Card, CardContent } from "@skyvexsoftware/stratos-sdk";

export default function MyPlugin() {
  const { airline, toast } = usePluginContext();
  const { isAuthenticated, user } = useShellAuth();

  if (!isAuthenticated) {
    return (
      <div className="flex h-full items-center justify-center">
        <p className="text-muted-foreground">Please log in to continue.</p>
      </div>
    );
  }

  return (
    <div className="p-6 space-y-4">
      <h1 className="text-2xl font-bold">
        Welcome, {user?.name ?? "Pilot"}
      </h1>

      <Card>
        <CardContent className="p-4">
          <p className="text-muted-foreground text-sm">
            Connected to {airline?.name ?? "your VA"}
          </p>
        </CardContent>
      </Card>

      <button
        className="text-sm text-primary underline"
        onClick={() => toast.success("Hello from My Plugin!")}
      >
        Send toast
      </button>
    </div>
  );
}