openHAB3 UI | How to write a custom widget with multiple slots

Hey everybody,

I’m trying to write a custom widget which shall expose two slots (header and content) like it’s done by some of the oh-* or f7-* widgets (e.g. f7-card expose header, content and a footer slot)

I’ll intend to use it in another widget like this:

    - component: widget:my-component
      slots:
        header:
          - component: Label
            config:
              text: 'Hello'
        content:
          - component: Label
            config:
              text: 'Some text'

Is this possible with custom widgets or limited to the provided oh-* or f7-* widgets?

Best regards
Jan

This does not make sense to me.
What are you trying to achieve?

I have a number of widgets, all with the same layout:

component: f7-block
config:
  style:
    background-color: "=props.bgcolor ? props.bgcolor : '#F7F7F7'"
    border-radius: var(--f7-card-expandable-border-radius)
    box-shadow: 0.25rem 0.25rem 0.5rem 0 rgba(0,0,0,0.1)
    margin: 0.25rem
    padding: 0.5rem 1rem
slots:
  default:
    - component: f7-block 
      config:
        style:
          align-items: center
          display: flex
          flex-direction: row
          margin: 0
          padding: 0
      slots:
        default:
          - component: oh-icon
            config:
              height: 1.25rem
              icon: <some icon>
              style:
                margin-right: 0.75rem
          - component: Label
            config:
              style:
                font-size: 1rem
              text: =props.title
    - component: f7-block
      config:
        style:
          margin: 0.75rem 0 0 0
          padding: 0
      slots:
        default:
        ... here comes the actual content ...

Its similar to the f7-card component, defining a card with a header and a content block and - most important - same spacing etc.

Instead of rewriting this snippet in every widget, I want to create one widget defining this layout, like the f7-card component, so I can use it the same way:

component: my-custom-card-widget
slots:
  header:
    - component: oh-icon
      config:
        height: 1.25rem
        icon: <some icon>
        style:
          margin-right: 0.75rem
    - component: Label
      config:
        style:
          font-size: 1rem
        text: =props.title
  content:
    ... here comes the actual content ...

With this solution I void avoid writing duplicate code in every widget. Furthermore I ensure every widget has the same layout and adjustments only need to be made once.

Yes it’s possible for exactly this sort of use case. Here’s a very basic example:

uid: demo:widget_with_slots
tags: []
props:
  parameters: []
  parameterGroups: []
component: f7-row
config:
  style:
    border: solid
slots: {}
uid: demo:use_widget_slots
tags: []
props:
  parameters: []
  parameterGroups: []
component: f7-block
config: {}
slots:
  default:
    - component: widget:demo:widget_with_slots
      slots:
        default:
          - component: oh-button
            config:
              text: Show this button

image

There are some limitations, of course. First, you cannot concatenate two slots together. If your template widget has a type of slot already defined it will get overwritten when you call that widget with a different version of that slot. If, in the example above, the demo:widget_with_slots also has a component in its default slot:

uid: demo:widget_with_slots
tags: []
props:
  parameters: []
  parameterGroups: []
component: f7-row
config:
  style:
    border: solid
slots:
  default:
    - component: oh-button
      config:
        text: This button will not be rendered

you will still get the same output as above because the This button will not be rendered component is overwritten by the Show this button component.

Second, you cannot create your own custom slot types. You are still limited to the slots that are available for your widget’s base component.

1 Like

Thanks for your reply :slight_smile:

The first restriction is not a problem, I expected it to be so.

However I had hoped that I could define some custom slot types. But at least I can style the f7-card component once the way I prefer with your solution. That already makes it much easier for me.