Widget reference

Buoy ships a set of React components plugin authors compose inside their render(ctx) callbacks. Every component is declared as a global by buoy-sdk.d.ts — no import needed.

For layout outside the widget catalog, plain DOM elements (<div>, <span>, <pre>) are also allowed.

KeyValue / Row

The most common widget. A titled section with label/value rows.

<KeyValue title="Quick facts">
  <Row label="Name" value={obj.metadata.name} />
  <Row label="Phase" value={obj.status?.phase} badge />
  <Row label="Node" value={obj.spec.nodeName} default="(unscheduled)" />
  <Row
    label="Owner"
    value={ref.name}
    link={{ kind: "Deployment", name: ref.name, namespace: obj.metadata.namespace }}
  />
</KeyValue>

<Row> props:

proptypenotes
labelstringThe dt cell.
valueunknownAuto-formatted. Objects render as JSON.
defaultstringRendered (muted) when value is null / undefined.
monobooleanMonospace font.
badgebooleanRender as a colored StatusBadge.
link{ kind, name, namespace?, resource? }Cell becomes a click-through deep link.

Pills / Pill

A horizontal row of colored chips. Use for headline status indicators.

<Pills title="State">
  <Pill label={obj.status.phase} tone={obj.status.phase === "Ready" ? "ok" : "warn"} />
  <Pill label={obj.spec.tier} tone="info" />
</Pills>

<Pill> tone: ok / error / warn / info / gray (synonyms accepted: good/green, bad/red, warning/yellow, blue).

One-line callout in a colored band. Conditionally render with regular JSX:

{obj.status.phase === "Failed" && (
  <Banner tone="error" text={`Pod failed: ${obj.status.message}`} />
)}

Same tone palette as <Pill>.

Section

Wrap a group of widgets in a titled container, optionally collapsible.

<Section title="Advanced" collapsible defaultOpen={false}>
  <KeyValue><Row label="UID" value={obj.metadata.uid} mono /></KeyValue>
</Section>

Conditions

Renders status.conditions[] as a tidy table. Hidden when the array is empty.

<Conditions from={obj.status?.conditions} />

The from prop accepts any array — usually status.conditions, but plenty of CRDs put conditions elsewhere.

Progress

Single horizontal progress bar.

<Progress
  title="Replicas"
  value={obj.status?.readyReplicas}
  max={obj.spec.replicas}
/>

value and max are coerced numerically; non-numbers fall back to 0 / 1.

StackedBar / Segment

N-segment bar for “buckets of a whole” visualizations (canary/stable weights, blue/green, status histograms).

<StackedBar title="Weights">
  <Segment value={obj.status.canary.weight} tone="info" label="canary" />
  <Segment value={100 - obj.status.canary.weight} tone="ok" label="stable" />
</StackedBar>

total overrides the implicit denominator (sum of segment values).

Table

Generic data table. You supply rows (any array) and columns describing each cell.

<Table
  title="Steps"
  rows={obj.spec.strategy.canary.steps}
  columns={[
    { header: "Step", cell: (_s, i) => `${i + 1}` },
    { header: "Weight", cell: (s) => s.setWeight ?? "—" },
    { header: "Pause", cell: (s) => s.pause?.duration ?? "" },
  ]}
  empty="No steps configured"
/>

Each column’s cell(row, idx) returns a ReactNode — return JSX, strings, numbers, or <CellValue> for the same auto-formatting / link / badge handling as <Row>.

RelatedList

Live watch over related resources by selector. Without custom columns, reuses the native ResourceTable so the embedded list looks like every other Buoy table.

<RelatedList
  title="Pods"
  kind="pods"
  labelSelector={obj.spec.selector?.matchLabels}
/>

With custom columns:

<RelatedList
  title="Owned ConfigMaps"
  kind="configmaps"
  labelSelector={{ "app.kubernetes.io/instance": obj.metadata.name }}
  columns={[
    { header: "NAME", cell: (row) => row.name },
    { header: "KEYS", cell: (row) => Object.keys(row.object.data ?? {}).length },
  ]}
/>

labelSelector accepts a kubectl-style string ("app=foo,tier=bar") or an object that’s joined the same way.

RelatedObject

Inline link card pointing to another resource. Children render alongside the link.

<RelatedObject
  title="Pod"
  kind="Pod"
  resource="pods"
  name={obj.status.podRef?.name}
  namespace={obj.metadata.namespace}
/>

Yaml

Pretty-prints a value (the whole object or a sub-tree) in the same CodeMirror viewer used elsewhere in Buoy.

<Yaml title="Spec" value={obj.spec} />

Markdown

Plain-text body in a monospace block. No markdown parsing (avoids the dep + XSS surface) — if you need structured content, use plain JSX.

<Markdown title="Notes" body={obj.status.notes} />

CellValue

The same auto-formatter <Row> and <Table> use under the hood. Call it directly when you need that behavior inside a custom JSX expression:

<CellValue value={obj.spec.image} mono link={{ kind: "Image", name: obj.spec.image }} />

Hooks

Call inside render(ctx) like any React hook.

useObject({ resource, name, namespace?, context? })

Live single-object watch. namespace / context default to the detail view’s. Returns { data, loading, error }.

const owner = useObject({ resource: "deployments", name: ownerRefName });
if (owner.loading) return <Banner tone="info" text="Loading owner…" />;

useList(resource, opts?)

Live list watch. opts.labelSelector accepts a string or an object; opts.allNamespaces overrides the namespace default. Returns the standard watch state ({ rows, columns, ready, error }).

const peers = useList("pods", {
  labelSelector: { app: obj.metadata.labels.app },
});

Hooks throw if called outside a plugin render(ctx) callback.


Edit this page on GitLab