Skip to main content

Display Components

Display components render content — text, images, and other read-only visual elements. They work on all three surfaces.

Text​

Renders a text string with typography variants.

Props​

PropTypeRequiredDescription
contentstringYesText content to display
variant"heading" | "default" | "muted"NoTypography preset (default: "default")
styleVisionStyleNoAdditional style (font size, color, etc.)

Variants​

VariantDescriptionUse case
"heading"Bold, larger font sizeSection titles, alert names
"default"Normal body textPrimary content, scores, labels
"muted"Dimmed, smaller fontTimestamps, 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​

PropTypeRequiredDescription
srcstringYesImage URL (must be in the egress allowlist for external URLs)
altstringYesAccessible alt text
objectFit"cover" | "contain" | "fill" | "none" | "scale-down"NoHow the image fills its container (default: "cover")
styleVisionStyleNoAdditional 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​

External image URLs must be in the egress allowlist in lumio.config.json:

{
"egress": {
"allowHosts": ["i.scdn.co", "*.spotifycdn.com"]
}
}

Internal Lumio CDN images (profile avatars, uploaded assets) do not require egress allowlist entries.


IconDisplay​

Renders any IconValue as the appropriate visual element.

Props​

PropTypeRequiredDescription
iconIconValue | nullYesThe icon to render
sizenumberNoSize in pixels (default: 24)
classNamestringNoCSS class for styling

Rendering behavior​

icon.typeRendered as
lucideInline SVG (24x24 viewBox, stroke-based)
emojiText span with the Unicode character
emote<img> with the CDN URL
upload<img> with the upload URL
nullEmpty 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​

PrincipleGuidance
Always provide alt textEvery Image needs a descriptive alt for accessibility
Use variant before custom stylePrefer variant="muted" over style={{ color: "#9ca3af" }} for consistency
Avoid fixed font sizes in the layerPrefer relative units or theme-aware values to maintain readability at different canvas sizes
Keep text conciseOverlay text should be scannable at a glance — keep labels under 40 characters