Skip to main content

ESPHome, Composed

Build touchscreen UIs and device configs with TSX — reusable components, real data binding, compiled to standard YAML.

Why ESPCompose?

Component-Based LVGL UIs

Build touchscreen interfaces from reusable components — Screen, Card, HStack, Button, and more.

Home Assistant Data Binding

Bind HA entities to UI with useHAEntity. Toggle lights, read state, control devices — no lambdas.

Type-Safe Everything

Auto-generated types for every ESPHome platform and UI component. Your IDE catches errors at build time.

Theming & Layout

Built-in dark and light themes, flex layouts, and a design system you can customize or extend.

Targets ESPHome Directly

Generates standard ESPHome YAML and triggers the compiler automatically — seamless from code to device.

Built on Node.js

Tap into TypeScript and the entire NPM ecosystem — use any package or tooling to power your build pipeline.

Before & After

ESPHome YAML
lvgl:
widgets:
- obj:
layout: flex
flex_flow: COLUMN
children:
- label:
text: "Dashboard"
- obj:
layout: flex
children:
- button:
id: office_btn
on_press:
- homeassistant.action:
action: light.toggle
data:
entity_id: light.office
children:
- label:
id: office_btn_label
text: "Office"
- button:
id: gym_btn
on_press:
- homeassistant.action:
action: light.toggle
data:
entity_id: light.gym
children:
- label:
id: gym_btn_label
text: "Gym"
binary_sensor:
- platform: homeassistant
entity_id: light.office
on_state:
- lvgl.label.update:
id: office_btn_label
text: !lambda |-
if (x) return "Office On";
return "Office Off";
- platform: homeassistant
entity_id: light.gym
on_state:
- lvgl.label.update:
id: gym_btn_label
text: !lambda |-
if (x) return "Gym On";
return "Gym Off";
ESPCompose TSX
import { useHAEntity } from "@espcompose/core";
import { Screen, VStack, Card, HStack, Button, Text } from "@espcompose/ui";
const HALight = ({ entity, text }) => {
const light = useHAEntity(entity);
return (
<Button
text={light.isOn ? `${text} On` : `${text} Off`}
onPress={() => { light.toggle(); }}
/>
);
};
export const Dashboard = ({ display }) => (
<lvgl displays={[display]}>
<Screen>
<VStack>
<Text variant="title" text="Dashboard" />
<Card>
<HStack>
<HALight entity="light.office" text="Office" />
<HALight entity="light.gym" text="Gym" />
</HStack>
</Card>
</VStack>
</Screen>
</lvgl>
);

Coming Soon

ESPCompose is in active development. Star the repo to follow along.

★ Star on GitHub

Get Involved

ESPCompose is open source and community-driven. Whether you want to report bugs, suggest features, contribute code, or just hang out — we'd love to have you.