Display Components
Display components render content - text, images, and other read-only visual elements. They work on both surfaces (editor and layer).
Text
Renders a text string with typography variants.
Props
| Prop | Type | Required | Description |
|---|---|---|---|
content | string | Yes | Text content to display |
variant | "heading" | "default" | "muted" | No | Typography preset (default: "default") |
style | VisionStyle | No | Additional style (font size, color, etc.) |
Variants
| Variant | Description | Use case |
|---|---|---|
"heading" | Bold, larger font size | Section titles, alert names |
"default" | Normal body text | Primary content, scores, labels |
"muted" | Dimmed, smaller font | Timestamps, secondary info, help text |
Example
import { Text, VStack } from "@zaflun/lumio-sdk";
function ScoreDisplay({ homeScore, awayScore, teamA, teamB }) {
return (
<VStack gap={4}>
<Text content={`${teamA} vs ${teamB}`} variant="heading" />
<Text content={`${homeScore} - ${awayScore}`} variant="default" />
<Text content="Live score" variant="muted" />
</VStack>
);
}
Custom styling
<Text
content="Breaking news!"
style={{
color: "#ef4444",
fontWeight: 700,
fontSize: 20,
letterSpacing: "0.05em",
textTransform: "uppercase",
}}
/>
Image
Renders an image with an accessible alt text.
Props
| Prop | Type | Required | Description |
|---|---|---|---|
src | string | Yes | Image URL (must be in the egress allowlist for external URLs) |
alt | string | Yes | Accessible alt text |
objectFit | "cover" | "contain" | "fill" | "none" | "scale-down" | No | How the image fills its container (default: "cover") |
style | VisionStyle | No | Additional style (width, height, border-radius, etc.) |
Example
import { Image, Box, Text, useLumioEvent } from "@zaflun/lumio-sdk";
function NowPlayingCard() {
const event = useLumioEvent("spotify:track");
if (!event) return null;
const track = event.data;
return (
<Box style={{ display: "flex", gap: 12, alignItems: "center" }}>
<Image
src={track.albumArtUrl}
alt={`Album art for ${track.album}`}
objectFit="cover"
style={{ width: 56, height: 56, borderRadius: 6, flexShrink: 0 }}
/>
<Box>
<Text content={track.title} variant="default" />
<Text content={track.artist} variant="muted" />
</Box>
</Box>
);
}
External images and egress
The host renders your UI outside the sandbox, so it loads an external image only when its host is in the egress allowlist in lumio.config.json. The URL must be https on the default port; anything else renders an empty placeholder and makes no request:
{
"egress": {
"allowHosts": ["i.scdn.co", "*.spotifycdn.com"]
}
}
These need no egress entry: data:image/* URLs, URLs on the Lumio page itself (relative URLs included), assets on your extension's own runtime origin, and the avatar, emote and badge URLs of Twitch, 7TV, BTTV, FFZ, YouTube, Discord and Kick that Lumio's image proxy serves. The same rule applies to the src of a plain <img> and the href of an <a>. A style value that loads something (url(), image-set(), …) is dropped; put background images in your stylesheet instead.
IconDisplay
Renders any IconValue as the appropriate visual element.
Props
| Prop | Type | Required | Description |
|---|---|---|---|
icon | IconValue | null | Yes | The icon to render |
size | number | No | Size in pixels (default: 24) |
className | string | No | CSS class for styling |
Rendering behavior
icon.type | Rendered as |
|---|---|
lucide | Inline SVG (24x24 viewBox, stroke-based) |
emoji | Text span with the Unicode character |
emote | <img> with the CDN URL |
upload | <img> with the upload URL |
null | Empty placeholder |
Example
import { IconDisplay } from "@zaflun/lumio-sdk";
import type { IconValue } from "@zaflun/lumio-sdk";
function AlertHeader({ icon }: { icon: IconValue | null }) {
return (
<HStack>
<IconDisplay icon={icon} size={32} />
<Text>Alert!</Text>
</HStack>
);
}
Display component guidelines
| Principle | Guidance |
|---|---|
Always provide alt text | Every Image needs a descriptive alt for accessibility |
Use variant before custom style | Prefer variant="muted" over style={{ color: "#9ca3af" }} for consistency |
| Avoid fixed font sizes in the layer | Prefer relative units or theme-aware values to maintain readability at different canvas sizes |
| Keep text concise | Overlay text should be scannable at a glance - keep labels under 40 characters |