Lovelace: React Custom Lovelace Card with `@preact/signals-react`

Hello!

I have been looking for an example where someone mounts a React component to a lovelace web component, but could not find any clean examples. So I made my own.

I have come up with a POC that mounts a React component to a web component’s shadow root.

The other issue is the repeated rendering when hass or config is changed. This can be solved very easily now with @preact/signals-react.

Pros:

  • React based Lovelace Card
  • Build the component with modern TS/TSX/JS/JSX
  • No need for HASS connectors - hass consumed directly from Home Assistant
  • Highly configurable
  • Use any other npm libraries

Cons:

  • Requires build step.
  • No direct pipelines (yet).
  • Can’t use Radix UI (because they use document.documentElement to deal with dark mode :sob:).

I’d like to hear comments and thoughts about this!

Super interested to see where this goes. Opens up a lot for folks with React skills who dont want to learn crazy yaml hacks

Wow, such great work! Thank you, @samuelthng !

Your README is simple, quick, and it works well.

I would like to know if you’ve found a way to live preview your card during development, similar to how we develop a classic React app. Perhaps simulate a config file outside of the Home Assistant instance? Also, if we update the .js file located in /local/www, how can we easily update the card?

I have to manually clear the browser’s cache.

I hope my questions are clear enough.

I haven’t been working on this, got put on a major project this year so all my personal projects have been dragged down lately :sob:

That aside, I haven’t found a fix for the stale js file, but what HACS does is include a cache breaker hash for each imported resource. If you’re keen to make some progress, I’m guessing that will be the direction eventually.

As for having a local version of the script, you could mock the value of the hass and config signal and replace it wherever required. Since it’s a signal, it’s gonna work no matter what updates it.

You can find the signals in utilities/registerCard.ts, might have to export the signals individually.

Edit: @Nycco sorry not sure why the post wasn’t replied to your comment.

Thanks for your answer @samuelthng

I managed to get past the cache problem using the browser’s inspector mode and a hard reload.

Regarding the local version, it’s quite easy to export the hass and config signal, but I don’t know how I can preview the project locally with the ‘npm run dev’ command, for example.

Do you have any suggestions?

You’d need to mount the app’s custom element on a page.

Currently it’s being registered as a custom element in registerCard.ts so you could make use of that and register the app as a custom component, then just consume it in the body of a html file.

Will need some tweaking to make it happen.

TL;DR;

  • createReactCard.tsx - Creates a custom element.
  • registerCard.ts - Sets up signals and registers the custom element (see web component).

Load the bundle in a page using a script tag, then place <react-card> somewhere in your html file.

Thanks @samuelthng
I will give a try.

Last question :wink: do you think there’s a way to get the Material Design icon of HA into the custom card? To use the icon property in the YAML custom card config.

Home Assistant loads icons on the dashboard using the <ha-icon icon="mdi:something" class="icon" > custom element. You won’t be able to load the icons when testing locally, but you can definitely use them in the app and have them load on the dashboard. (I think, not sure if there are any caveats)

1 Like