UI components
The components, props and input behavior available to CodeMux add-on views.
Add-on views use Preact JSX with the components on this page. CodeMux draws them with its own components, so they follow the user's theme automatically. There's no HTML, CSS, SVG or image loading. Props accept fixed values called tokens, never style strings.
import { Card, Stack, Text, Badge, Button } from "@codemux/plugin-sdk";
<Card title="Build status" spacing="sm">
<Stack direction="horizontal" spacing="sm" align="center">
<Badge color="success">Passing</Badge>
<Text color="muted" size="sm">main · 2 minutes ago</Text>
</Stack>
<Button onPress={(event) => refresh(event.context)}>Refresh</Button>
</Card>Each component has a props type, such as StackProps or TextFieldProps. A value
outside the allowed range fails type checking. If one reaches CodeMux anyway,
CodeMux rejects the update and stops the add-on.
Components
| Component | Props |
|---|---|
Stack | direction (vertical | horizontal), spacing, align |
Grid | columns (1–12), spacing, align |
Card | title, spacing, align |
Text | Text children |
Badge | Text children |
Heading | level (1–6), text children |
Markdown | Markdown text children. HTML and images are removed. HTTPS links open through CodeMux and need external.open |
Button | label or children, disabled, onPress |
TextField, TextArea | label, value, placeholder, disabled, onChange (event.value is a string) |
Select | label, options ({ label, value }[]), value, disabled, onChange |
Checkbox, Switch | label, checked, disabled, onChange (event.value is a boolean) |
Tabs | label, options, value, disabled, onChange. Children are the content of the selected tab |
List | items (up to 500 strings), label |
Table | headers, rows (up to 500 rows of up to 20 strings), label |
Progress | value, max, label |
Icon | name (see Icons), label, color |
Divider | — |
EmptyState | title, children |
On List, Table and Icon, label is the accessible name. CodeMux virtualizes
long lists and tables, so use List or Table rows for large data instead of
many Text nodes.
There's no alert or toast component. To show a problem, use Text or Badge with
a color, or EmptyState. For a short message outside the view, use
ctx.ui.notify.
Shared props
Every component except Icon and Divider also accepts:
| Prop | Values |
|---|---|
size | xs, sm, md, lg |
color | default, muted, success, warning, danger, accent |
width, height | auto, full |
Layout props:
| Prop | Values |
|---|---|
spacing | none, xs, sm, md, lg |
align | start, center, end, stretch |
Strings such as label, title and placeholder can be up to 4 KiB. Text
children and field values can be up to 32 KiB.
Events
Only Button has onPress. Only TextField, TextArea, Select, Checkbox,
Switch and Tabs have onChange. Every callback gets { context, value }:
contextis a fresh context handle with a user interaction. Use it forappendText,links.openand opening views.valueis the new value of an input.onPressdoesn't set it.
A callback can be async. If it rejects with a PluginError, CodeMux records it and
the add-on keeps running. If it throws synchronously or rejects with anything
else, the add-on stops. See Faults.
Inputs
TextField and TextArea keep the text locally while the user types and report
every change through onChange. The value you render replaces that text only
when it's different from the last value the field reported. Rendering the value
back never moves the cursor or drops keystrokes. A field without value is
uncontrolled.
const [title, setTitle] = useState("");
<TextField
label="Title"
value={title}
onChange={(event) => setTitle(event.value)}
/>Select, Checkbox, Switch and Tabs always show the value or checked you
render, so update your state in onChange:
const [tab, setTab] = useState("open");
<Tabs
label="Issues"
value={tab}
options={[{ label: "Open", value: "open" }, { label: "Closed", value: "closed" }]}
onChange={(event) => setTab(event.value)}
>
{tab === "open" ? <OpenIssues /> : <ClosedIssues />}
</Tabs>onChange runs on every keystroke. Don't make a host request each time. Save when
the user clicks a button, or after a pause.
Rendering limits
Each view can have up to 2,000 nodes, 32 levels of nesting and 256 KiB of state, and four views can be open at once. If an update goes over a limit, even for a moment, CodeMux rejects the whole update and stops the add-on.
The SDK combines updates into about 16 batches per second and keeps only the latest value of each prop. Small changes to existing content work better than replacing large parts of the tree.