Skip to main content

Component Catalog

All components are imported from @espcompose/ui. They accept theme-driven design tokens and compile to LVGL widget trees.

Layout Components

Screen

Top-level page wrapper. Each <Screen> compiles to an <lvgl-page>.

PropTypeDefaultDescription
paddingSpacingTokenInner padding
skipbooleanfalseExclude from LVGL page cycling (useful for boot screens)
<Screen padding="lg">
{/* Page content */}
</Screen>

Space / VStack / HStack

Flexible layout container that arranges children with direction and gap. VStack and HStack are convenience wrappers.

PropTypeDefaultDescription
direction'horizontal' | 'vertical''vertical'Layout direction
gapSpacingTokenGap between children
paddingSpacingTokenInner padding
alignFlexAlignMain-axis alignment ('start', 'center', 'end', 'spaceBetween', 'spaceAround', 'spaceEvenly')
crossAlignCrossAlignCross-axis alignment ('start', 'center', 'end', 'stretch')
wrapbooleanAllow wrapping
<VStack gap="md" align="center">
<Text text="Item 1" />
<Text text="Item 2" />
</VStack>

<HStack align="spaceBetween" crossAlign="center">
<Text text="Label" />
<Switch />
</HStack>

Row / Col

Grid-like horizontal layout inspired by Ant Design. Row wraps by default; Col uses proportional width via flexGrow.

Row PropsTypeDefaultDescription
gutterSpacingToken | [SpacingToken, SpacingToken]Gap between columns (single or [horizontal, vertical])
justifyFlexAlign'start'Horizontal alignment
alignCrossAlign'start'Vertical alignment
wrapbooleantrueAllow wrapping
Col PropsTypeDefaultDescription
spannumber1Proportional width (flexGrow)
<Row gutter="md">
<Col span={1}>
<Text text="Left" />
</Col>
<Col span={2}>
<Text text="Right (wider)" />
</Col>
</Row>

Grid / GridItem

Native CSS Grid layout with explicit columns and rows.

Grid PropsTypeDefaultDescription
columnsTrackSize[]requiredColumn definitions: 'fr(n)', 'content', or pixel number
rowsTrackSize[]requiredRow definitions
columnGapSpacingTokenGap between columns
rowGapSpacingTokenGap between rows
gapSpacingTokenShorthand for both gaps
GridItem PropsTypeDefaultDescription
colnumberrequiredColumn position (0-based)
rownumberrequiredRow position (0-based)
colSpannumber1Number of columns to span
rowSpannumber1Number of rows to span
<Grid columns={['fr(1)', 'fr(1)']} rows={['content', 'content']} gap="sm">
<GridItem col={0} row={0}><Text text="Top Left" /></GridItem>
<GridItem col={1} row={0}><Text text="Top Right" /></GridItem>
<GridItem col={0} row={1} colSpan={2}><Text text="Full Width" /></GridItem>
</Grid>

Card

Styled container with rounded corners and themed background.

PropTypeDefaultDescription
paddingSpacingToken'md'Inner padding
radiusRadiusToken'md'Border radius
gapSpacingTokenGap between children
<Card padding="lg" radius="lg">
<Text variant="subtitle" text="Settings" />
<Slider min={0} max={100} />
</Card>

Control Components

Button

Interactive button with optional label. Supports solid and outline variants with semantic status colors.

PropTypeDefaultDescription
textstringButton label text
statusStatusToken'primary'Color scheme: 'primary', 'secondary', 'success', 'warning', 'danger'
sizeSizeToken'md'Size preset: 'xs', 'sm', 'md', 'lg', 'xl'
variant'solid' | 'outline''solid'Visual style
onPressTriggerHandlerPress event handler
<Button text="Save" status="success" size="lg" onPress={() => { /* save */ }} />
<Button text="Delete" status="danger" variant="outline" onPress={() => { /* delete */ }} />

Slider

Horizontal slider control with themed track, indicator, and knob.

PropTypeDefaultDescription
valuenumberCurrent value (reactive)
minnumber0Minimum value
maxnumber100Maximum value
onChangeTriggerHandler<{ x: number }>Value change handler
<Slider min={0} max={255} onChange={({ x }) => { brightness.set(x); }} />

Switch

Toggle switch control with themed rail and knob.

PropTypeDefaultDescription
valuebooleanCurrent state (reactive)
onChangeTriggerHandler<{ x: boolean }>State change handler
<HStack align="spaceBetween" crossAlign="center">
<Text text="Night Mode" />
<Switch value={nightMode.value} onChange={({ x }) => { nightMode.set(x); }} />
</HStack>

Dropdown selection control.

PropTypeDefaultDescription
optionsstringrequiredNewline-separated list of options
valueunknownSelected value (reactive)
onChangeTriggerHandler<{ x: number }>Selection change handler (index)
<Dropdown
options={"Option A\nOption B\nOption C"}
onChange={({ x }) => { selection.set(x); }}
/>

Display Components

Text

Semantic text display with theme-driven typography.

PropTypeDefaultDescription
textstringText content (reactive)
variantTextVariant'body'Typography scale: 'title', 'subtitle', 'body', 'caption'
align'left' | 'center' | 'right' | 'auto'Text alignment
colorStatusTokenOverride text color with a status color
longMode'WRAP' | 'DOT' | 'SCROLL' | 'SCROLL_CIRCULAR' | 'CLIP'Long text behavior
<Text variant="title" text="Dashboard" />
<Text variant="caption" text="Last updated: 5m ago" color="secondary" />

SensorText

Text display automatically driven by a Home Assistant entity binding's stateText.

PropTypeDefaultDescription
bindingSensorBinding | BinarySensorBinding | LightBindingrequiredEntity binding from useHAEntity()
textstringOptional static prefix/label
variantTextVariantTypography scale
colorStatusTokenOverride text color
const temp = useHAEntity('sensor.temperature');
<SensorText binding={temp} variant="title" />

Image

Image display widget with size presets and optional border radius.

PropTypeDefaultDescription
srcRef<ImageRef>requiredImage ref from useImage()
sizeSizeTokenSize preset
radiusRadiusTokenBorder radius
anglenumberRotation angle in degrees
zoomnumberZoom factor
antialiasbooleanEnable anti-aliasing
const logo = useImage({ file: './assets/logo.png', type: 'RGB' });
<Image src={logo} size="lg" radius="md" />

Spinner

Loading spinner with theme-driven colors.

PropTypeDefaultDescription
statusStatusToken'primary'Color scheme
sizeSizeToken'md'Size preset
arcLengthnumber60Arc length in degrees
durationnumber1000Animation duration in milliseconds
<Spinner status="primary" size="lg" />

Design Token Types

These token types are shared across all components:

TokenValues
SpacingToken'none', 'xs', 'sm', 'md', 'lg', 'xl'
SizeToken'xs', 'sm', 'md', 'lg', 'xl'
RadiusToken'none', 'sm', 'md', 'lg', 'full'
StatusToken'primary', 'secondary', 'success', 'warning', 'danger'
TextVariant'title', 'subtitle', 'body', 'caption'

See Theming for how these tokens map to actual pixel values and colors.