New feature in Main UI: Iconify support for icons

Hi all,

In this post I wanted to explain the feature recently added in the main UI (oh-icon component improvements, Iconify icon support by ghys · Pull Request #1149 · openhab/openhab-webui · Git) and what it means for users and widget authors.

The first obvious change is that from now on, the oh-icon component that you might as a widget author assimilated to be for only displaying openHAB icons, now can display icons from several sources, if you specify the icon property with a prefix. Those are:

Backwards compatibility is paramount so if you are already using the oh-icon component to display OH icons, don’t worry, if you don’t have a prefix with a colon : in the icon parameter, it will be assumed to be a OH icon like before.

The Iconify icon source

To help with the authoring of widgets, the Iconify source (iconify:, if: as a shorthand alias) has been added as a way to get more icons - it’s a online service curating dozens of iconsets with more than 100,000 icons in total. It’s important to note that you need an internet connection to fetch the icons initially from https://api.iconify.design, so you need to trust the service as well. If you don’t, or want everything locally, I’ll provide an alternative below.

Iconify icons are cached in the browser’s local storage the first time they are accessed, so as long as you don’t purge your local browser storage, the icons won’t be retrieved from the “cloud” once they’re in the cache.

Example

You want a fire extinguisher icon, but didn’t find any that suited in the built-in iconsets.

So after searching on https://icon-sets.iconify.design you find this icon:

All you have to do now to integrate it, is to use the iconify:<iconSet>:<iconName> syntax, like this:

component: oh-button
config:
  round: true
  outline: true
  class:
    - margin
    - display-flex
    - flex-direction-column
  style:
    height: auto
slots:
  default:
    - component: oh-icon
      config:
        height: 200px
        icon: iconify:noto:fire-extinguisher
        class:
          - padding
    - component: Label
      config:
        text: A Fire Extinguisher Button
        style:
          font-size: 30px
        class:
          - margin-left-half
          - margin-bottom

image

Note that this particular icon doesn’t support colors, because it has some of its own, but most of those which are monochrome do, so you can use the iconColor property when appropriate. Also note that certain components using oh-icon under the hood now support this source as well, not just oh-icon itself:

Example:

component: f7-list
config:
  mediaList: true
slots:
  default:
    - component: oh-list-item
      config:
        title: Tesla Model 3
        icon: iconify:simple-icons:tesla
        iconColor: green
        badge: ONLINE
        badgeColor: green
    - component: oh-list-item
      config:
        title: Audi Q5
        icon: iconify:simple-icons:audi
        iconColor: teal
        badge: UNKNOWN
        badgeColor: teal
    - component: oh-list-item
      config:
        title: BMW 720i
        icon: iconify:simple-icons:bmw
        iconColor: green
        badge: ONLINE
        badgeColor: green
    - component: oh-list-item
      config:
        title: Mercedes GLC
        icon: iconify:simple-icons:mercedes
        iconColor: red
        badge: OFFLINE
        badgeColor: red

image

(icons found in Simple Icons • Iconify)

However native Framework7 components and derivatives do not support icons beyond what they were designed to support (namely Framework7 and Material icons), so YMMV. But most openHAB components will - check the descriptions in the components’ docs as they will mention Iconify as a source if they support it.

What if I don’t want to rely on a remote service to display my icons?

That’s fine, oh:/f7:/material: icons are still fetched locally. If you like some of the Iconify icons that you find and want to use them completely offline, you have a couple of options:

So let’s say you want to use this icon server security • Material Design Icons • Iconify in your widget:

And let’s say to want it in red so you specify red or #ff0000 in the “color” text box.

If you click on the “SVG” button and then the “SVG as data: URI” buttons, you’ll end up with some encoded SVG code:

Now what you have to do is add this code to the background: CSS style of one of your UI components, the simplest being Label, and the icon will be rendered locally, without any additional network request (add center / contain no-repeat at the end):

component: Label
config:
  style:
    background: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%221em%22%20height%3D%221em%22%20preserveAspectRatio%3D%22xMidYMid%20meet%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cpath%20d%3D%22M3%201h16a1%201%200%200%201%201%201v4a1%201%200%200%201-1%201H3a1%201%200%200%201-1-1V2a1%201%200%200%201%201-1m0%208h16a1%201%200%200%201%201%201v.67l-2.5-1.11l-6.5%202.88V15H3a1%201%200%200%201-1-1v-4a1%201%200%200%201%201-1m0%208h8c.06%202.25%201%204.4%202.46%206H3a1%201%200%200%201-1-1v-4a1%201%200%200%201%201-1M8%205h1V3H8v2m0%208h1v-2H8v2m0%208h1v-2H8v2M4%203v2h2V3H4m0%208v2h2v-2H4m0%208v2h2v-2H4m13.5-7l4.5%202v3c0%202.78-1.92%205.37-4.5%206c-2.58-.63-4.5-3.22-4.5-6v-3l4.5-2m0%201.94L15%2015.06v2.66c0%201.54%201.07%202.98%202.5%203.34v-7.12z%22%20fill%3D%22red%22%2F%3E%3C%2Fsvg%3E') center / contain no-repeat
    height: 100px

image

Please note that this approach has caveats, it increases the weight of your widget code, and you can’t benefit from the caching features of the regular API.

Hope it helps!

12 Likes

Hello, is there any plan to add Iconify support to the old sitemap syntax? Thanks.

That’s awesome stuff - thank you.

I am already using it successfully by:

icon: "=items[props.door_state].state === 'OPEN' ? 'iconify:bi:door-open' : 'iconify:bi:door-closed'"

but how to scale the size of the icon in this syntax?
The regular parameters in “style” don’t seem to work.

iconSize: 20
                    icon: "=items[props.door_state].state === 'OPEN' ? 'iconify:bi:door-open' : 'iconify:bi:door-closed'"
                    style:
                      height: 18px

Thank you, Hans-Jörg,

Unfortunately this does not work either:

config:
              icon: "=items[props.door_state].state === 'OPEN' ? 'iconify:bi:door-open' : 'iconify:bi:door-closed'"
              iconColor: "=themeOptions.dark === 'dark' ? 'white' : 'orange'"
              style:
                bottom: -22px
                height: 24px
                left: 120px
                position: absolute

the height parameter just shifts the icon up and down (this is with height: 44px)
image

Please show your complete component config.

sure - thank you:

component: f7-card
config:
  style:
    background-color: "=props.bgcolor ? props.bgcolor : ''"
    background-image: "=props.bg_image_url ? 'url(/static/backgrounds/' + (props.bg_image_url) + ')' : ''"
    border-radius: var(--f7-card-expandable-border-radius)
    box-shadow: 5px 5px 10px 1px rgba(0,0,0,0.1)
    class:
      - padding: 0px
    height: 140px
    margin-left: 5px
    margin-right: 5px
    noShadow: false
slots:
  content:
    - component: f7-block
      config:
        style:
          left: 45px
          position: absolute
          top: -5px
      slots:
        default:
          - component: Label
            config:
              style:
                font-size: 17px
                font-weight: 600
                margin-left: 0px
                margin-top: 0px
              text: "=props.text_header ? props.text_header : 'Set Props'"
    - component: f7-block
      config:
        style:
          bottom: 2px
          left: 5px
          position: absolute
      slots:
        default:
          - component: oh-link
            config:
              iconColor: "=themeOptions.dark === 'dark' ? 'white' : 'orange'"
              iconF7: "=items[props.alarm_mode].state === 'ON' ? 'alarm' : 'alarm_off'"
              iconSize: 20
              style:
                left: 20px
                position: absolute
              visible: "=props.alarm_mode ? true : false"
          - component: oh-link
            config:
              iconColor: "=themeOptions.dark === 'dark' ? 'white' : 'orange'"
              iconF7: "=items[props.status_lock].state === 'ON' ? 'lock' : 'lock_open'"
              iconSize: 20
              style:
                left: 50px
                position: absolute
              visible: "=props.status_lock ? true : false"
          - component: oh-link
            config:
              iconBadge: "=(items[props.status_light].state > 0) ? items[props.status_light].state : ''"
              iconColor: "=themeOptions.dark === 'dark' ? 'white' : 'orange'"
              iconF7: "=(items[props.status_light].state === 'ON' ) ? 'lightbulb_fill' : (items[props.status_light].state === 'OFF' ) ? 'lightbulb' : (items[props.status_light].state > 0 ) ? 'lightbulb_fill' : 'lightbulb' "
              iconSize: 20
              style:
                left: 85px
                position: absolute
          - component: oh-icon
            config:
              icon: "=items[props.door_state].state === 'OPEN' ? 'iconify:bi:door-open' : 'iconify:bi:door-closed'"
              iconColor: "=themeOptions.dark === 'dark' ? 'white' : 'orange'"
              style:
                bottom: -22px
                height: 44px
                left: 120px
                position: absolute

It’s about the last part (oh-icon) with the door state

Sorry, for oh-icon it is “width” :

config:
              icon: "=items[props.door_state].state === 'OPEN' ? 'iconify:bi:door-open' : 'iconify:bi:door-closed'"
              iconColor: "=themeOptions.dark === 'dark' ? 'white' : 'orange'"
              style:
                bottom: -22px
                height: 24px
                width: 36
                left: 120px
                position: absolute

The iconify icons are svg elements so scaling manually is a little trickier. Most of them should be properly defined in em units so the best bet is just to use fontSize in the oh-icon.

- component: oh-icon
  config:
    icon: "=items[props.door_state].state === 'OPEN' ? 'iconify:bi:door-open' : 'iconify:bi:door-closed'"
    iconColor: "=themeOptions.dark === 'dark' ? 'white' : 'orange'"
    style:
      bottom: -22px
      left: 120px
      position: absolute
      fontSize: 18px
1 Like

both are working!

Thank you, Justin & Hans-Jörg!

1 Like