Fundamentals

UI Components

Build rich extension UIs with the @oxprotocol/ui component vocabulary.

@oxprotocol/ui provides a frozen V1 component vocabulary for building extension interfaces. Authors compose a tree of typed components; hosts render them natively (Piye) or via the DOM backend (VS Code webview).

The Component Set

OXP V1 ships exactly six components. New components require a spec bump — this vocabulary is intentionally small and stable.

ComponentPurposeContainer
BoxGeneric container with padding and gap
StackFlexbox-style vertical or horizontal layout
TextText content with variant styling
ButtonClickable action trigger
VirtualListEfficiently render large lists
CodeBlockSyntax-highlighted code display

Basic Usage

typescript
import { Stack, Text, Button } from "@oxprotocol/ui";
import { defineExtension } from "@oxprotocol/sdk";

export default defineExtension({
  activate(host) {
    host.renderTree(
      Stack({ gap: 2 }, [
        Text("Hello, OXP!", { variant: "heading" }),
        Text("Build once. Install everywhere."),
        Button({ label: "Get Started", action: "start", variant: "primary" }),
      ])
    );
  },
});

Component Reference

Box

Generic container with padding and gap.

typescript
Box({ pad: 4, gap: 2 }, [
  Text("Inside a box"),
])
PropTypeDescription
pad`0 \1 \2 \3 \4 \6 \8`Padding (spacing scale)
gap`0 \1 \2 \3 \4 \6 \8`Gap between children
childrenUiNode[]Child components

Stack

Flexbox layout — vertical or horizontal.

typescript
Stack({ axis: "horizontal", gap: 2, align: "center" }, [
  Button({ label: "Save", action: "save" }),
  Button({ label: "Cancel", action: "cancel", variant: "ghost" }),
])
PropTypeDefaultDescription
axis`"vertical" \"horizontal"`"vertical"Layout direction
gapspacing scaleGap between children
align`"start" \"center" \"end" \"stretch"`Cross-axis alignment

Text

typescript
Text("Hello", { variant: "heading" })
PropTypeDescription
valuestringThe text content (first argument)
variant`"body" \"heading" \"caption" \"code"`Visual style

Button

typescript
Button({ label: "Run", action: "run-task", variant: "primary", disabled: false })
PropTypeDescription
labelstringButton text
actionstringAction ID sent to the host on click
variant`"primary" \"secondary" \"ghost" \"danger"`Visual style
disabledbooleanDisable interaction

VirtualList

Efficiently renders large lists. The host may virtualize based on item count.

typescript
VirtualList({
  items: data.map(item => Text(item.name)),
  rowHeight: 28,
})

CodeBlock

typescript
CodeBlock({ value: "const x = 42;", language: "ts" })

Tree Validation

The validateTree() function checks that every node in a tree uses a known V1 component kind. It's used by oxp pack to reject bundles with non-V1 nodes, and by hosts as a runtime guard.

Render Modes

ModeDescription
DOM renderer@oxprotocol/ui/dom — renders the tree to real DOM elements in a webview. Used by the VS Code host.
Native rendererHost implements the component set in its native toolkit. Used by Piye (GPUI). Same .oxp bundle, 120fps native UI.

The beauty of the component vocabulary is that your extension doesn't need to know which renderer is active. The same tree works everywhere.