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