TailwindCSS Template Card - build custom cards with HTML and TailwindCSS

Hey guys! Thinking about the discomfort and complication that are common during the development of custom cards for our dashboards and at the same time fascinated with the potential of TailwindCSS, an incredible tool that I discovered a few months ago, I started to research and experiment with ways to be able to use TailwindCSS with Home Assistant.

At first there were several unsuccessful attempts, but it was a matter of searching with the right keywords to find the right path to follow.
Eventually, I got to the point where I am now, very excited about what I built and hopeful that more people will start using TailwindCSS, which I believe could be a game changer in custom card development, due to the ease and agility of development and maintenance.

I would like to announce to everyone the “TailwindCSS Template Card”, a custom card whose functionality the name already says: render templates (HTML with Jinja) with TailwindCSS!
tailwindcss-in-dash-480p

Still don’t understand how exciting this is? Take a look at the gif below that demonstrates real-time rendering of HTML templates with TailwindCSS . Also check out the examples I added in the project’s README.
tailwindcss-template-card-480p

6 Likes

How would you create a button with an action to call a service in HA?

Since the version v1.2.0, ou can use the hass object inside the onClick handler:

type: custom:tailwindcss-template-card
content: |
  <div onClick="hass.callService('homeassistant', 'toggle', {entity_id: 'light.hall'})" class="bg-slate-600 w-fit h-fit p-5 rounded-2xl m-auto
  hover:scale-105 transition-all cursor-pointer">
    Click me
  </div>

Result:
example-with-control

1 Like

Actually you can use the hass object anywhere in JavaScript inside your content, not only inside onClick

Tx for your help. I’m going to try this out.

Do you have any idea how we can integrate / use use ui kits like https://daisyui.com/ , tailwind-elements.com , etc? Is it possible to code these in your component or provide a way for us to do it ourselves?

Bad news and good news!

Bad news: no it isn’t possible to integrate such plugins in tailwindcss-template-card because apparently twind (the tool i use for bringing TailwindCSS into HomeAssistant cards) API is not compatible with the TailwindCSS plugins API (or the other way around).
You can get more context here and here

Now the good news:
I got daisyUI working with tailwindcss-template-card simply by injecting the daisyUI full CSS (downloaded from CDN) into the shadowRoot of the card, just like i do with Twind.
And it’s already available for you to test it! Check the release v1.3.0, which you can already download from hacs (yet using the repo as custom repo):
Release v1.3.0 · usernein/tailwindcss-template-card · GitHub

It supports DaisyUI out-of-box, so you just need to install/update the card and start using daisyUI classes. I tested a bunch of them and even modals work, but only modals using the hidden checkbox approach. I couldn’t get modals with dialog tag to work.

Ah, and i didn’t try to do the same with tailwind-elements.com yet

Actually i didn’t even know about it, so it would take a little bit of time to integrate it, if it’s possible

My main objective now is to provide a configuration screen so users can choose if they want to use DaisyUI and any other future supported plugins, so the card does not do unecesary downloads.

I also want to provide a way to let the user choose an specific version of daisyui and even let they provide a custom url for the download, because i know there are many users out there who have offline installations of home assistant, so i should not force the card to always download online from CDN

Top job! Thank you very much. As it can be loaded from CDN, maybe we can download all the packages and include them in yaml pointing to a local repository?

Yeah, it’s possible! That’s what i meant when i said about custom url for download

1 Like

Check out the version v1.4.1! It brings some new tweaks for the card and DaisyUI usage, as well as a brand new visual config editor, built with DaisyUI!!!

tailwindshort

This is awesome :ok_hand:. U rock mate! I’m going to give this a try next weekend. This is opening the door to some real nice custom designs. Woop woop.

1 Like

I’m building a card for my lights using a daisyui slider. I can see the elements in the frontend, so that’s fine, but now I’m stuck. I can call the service providing a hard coded brightness_pct, but I have no clue how to get the value of the slider in the Hass.callservice. Do you have something to guide me or do you know how to use javascript functions in your component?

1 Like

Awesome! That’s actually very easy to accomplish: you need to get the value from HomeAssistant with Jinja templates. It will update your card with the new state whenever your entities updates. e.g.:

<input
    type="range"
    class="range range-accent"
    min="0" max="100"
    value={{ states('input_number.test') }}
    onChange="hass.callService('input_number', 'set_value', { entity_id: 'input_number.test', value: this.value })"
/>

Thx for the reply. Do I need to create a home assistant element for this? I don’t want to create separate home assistant elements for this. I can put the value of a home assistant element I the range selector from tailwind. That’s already working.

Now I would like to get the value from the tailwind range selector and put that value in the hass.callservice of a button to set the brightness of my light according to the selected value of the tailwind range selector.

Nah, you don’t need to create a separated element for it, you can do it all with a single html except with tailwindcss-template-card

About sending the values from tailwind to hass services, check the example i posted earlier here, it contains a slider based on input[type="range"] that automatically changes its value following the input_number.test value and tells to home assistant, with callService, the slider value when you interact with it.

So it’s a two-way synced element, if that makes sense. The rendered HTML will update itself on any entity state change automatically (if you use the entity in jinja templates within your html content) and you can pass the any values from your HTML to home assistant with the hass object in javascript.

That’s made with simple javascript: use this.value inside the onChange handler.

References:
About the object this in inline event handlers: this - JavaScript | MDN
About the object hass: Frontend data | Home Assistant Developer Docs

Another example of two-way synced elements:
toggle

In the example above, the first card is a native Tile card and the second one is a tailwindcss-template-card.

HTML Content:

<div class="flex flex-col">
  <div class="form-control h-12 justify-center w-full">
    <label class="cursor-pointer label">
      <span class="label-text">{{state_attr('input_boolean.notifications','friendly_name')}}</span> 
      <input type="checkbox" class="toggle toggle-primary" {{ iif(is_state('input_boolean.notifications', 'on'), "checked", "") }} onChange="hass.callService('homeassistant', 'toggle', { entity_id: 'input_boolean.notifications' })" />
    </label>

The {{ iif(is_state('input_boolean.notifications', 'on'), "checked", "") }} will insert the attribute “checked” to the input tag if the state of input_boolean.notifications equals to “on”. That’s called immediate if and it’s a function from Jinja.

Note that i don’t pass any value to callService because it can only be false or true, so i just call toggle. And the input will always be updated with the value from home assistant, so i don’t have to worry about the card showing true while the entity value it’s actually false. I just call toggle and let Jinja do its job to fetch the updated value and refresh the card.

Reference:
Immediate If (IIF): Templating - Home Assistant

This is a GIF of the first example i sent:
slider-tw

The DaisyUI theme used here is halloween, if anyone is interested

Hi mate. We’re not on the same page here :grin:. I want to be able to adjust the brightness of a light using a range slider. Here’s my code:

<div class="card w-full bg-base-100 shadow-xl">
  <figure><img src="/local/images/ui_elements/lamp-kort.png" alt="Keuken" /></figure>
  <div class="card-body">
    <h2 class="card-title">
      Keuken
      <div class="badge badge-secondary"> {{ 'fout' if is_state('light.lichten_keuken', 'unavailable') else ''}} </div>
    </h2>
    <p>This is a light card wip</p>

    <div class="card-actions"> 
<button class="btn btn-wide {{ 'btn-success' if is_state('light.lichten_keuken', 'on') else ''}}" onClick="hass.callService('homeassistant', 'toggle', {entity_id: 'light.lichten_keuken'})">{{ 'aan' if is_state('light.lichten_keuken', 'on') else 'uit'}}</button>
<div class="flex">
  <div class="flex-auto w-64">
    <input type="range" min="0" max="100" value="70" class="range range-lg pr-10" />
  </div>
  <div class="flex-auto w-32">
    <input type="checkbox" class="toggle toggle-success toggle-lg" {{ 'checked' if is_state('light.lichten_keuken', 'on') else 'unchecked'}} onClick="hass.callService('homeassistant', 'toggle', {entity_id: 'light.lichten_keuken'})" />
  </div>
  
</div>


</div>
<div class="card-actions justify-end"> 
      <div class="badge badge-outline">{{expand('light.lichten_keuken')|selectattr('state','eq','on')|list|count}} / {{expand('light.lichten_keuken')|list|count}}</div> 
      <div class="badge badge-outline">
{{states('light.lichten_keuken')}} 
{% if(is_number(state_attr('light.lichten_keuken', 'brightness')))%}
{% set bri= state_attr('light.lichten_keuken', 'brightness')%}
{% set bri = (bri/2.55)|round(0)%}
{%else%}
{% set bri=0%}
{%endif%}
{{bri}}
%</div>
    </div>
  </div>
</div>

How can I get the changes I make using the slider in tailwind to trigger a change on the light brightness? I can toggle a light using tailwind and I can set a fixed brightness, but i don’t know how to set the brightness based on the value of the slider.

I hope this feedback will give you some guidance. I really love this approach and I strongly believe this project has huge potential for nice dashboards.

Currently I’m seeing a lot of latency and I didn’t build many components in the same view yet. Benchmarking is done comparing tailwind elements in my view with native elements from home assistant in the same view.

  1. Very often tailwind components are not loaded at all or very slow. Native components show instantly.
  2. Changing entity status is not immediately visible in the tailwind elements (using the predefined classes to reflect a change). Ex: green color of a button means status is on and no color is reflecting status off.
  3. Changing status of a device (only tested light) is picked up instantly using the onclick event with the hass services.

Would the impact of running this setup locally (not loading the entire framework over and over again from the cloud) have a positive result?
Can we cache the tailwind framework once loaded to speed up loading times?