How To Build A Custom Widget

I just bought two new matter connected air purifiers (so far, I am quite pleased with them). It turns out, that there isn’t a built-in MainUI widget to display the function and controls for an air purifier, so I’m going to have to make one.

This is intended to be the first in a set of tutorials where I’m going to go through my process of widget creation. I’ve got two main goals here. First, I hope these tutorials help cast some light on the aspects of custom widget creation many users find difficult. Secondly, I want to showcase the many resources that are available for widget creators (novice and expert alike).

Custom widget tutorials

1. How do I know where to start?

There has been a lively recent debate about how much technical expertise an OH user needs to become proficient at creating widgets. It’s too long to recap here, but the central question became “what level of HTML and CSS understanding does a user need to be successful at widget creation”. The good news is that for basic widget creation the answer is almost none. The OH widget system presents many preconfigured options that get us up and running with almost no detailed configuration. But, before we can even get to the configuration step, we have to know what we want.

My purifiers present four channels to OH:

  1. WiFi connection strength (Number:Power)
  2. Air Quality (Number 1 = Good, 6 = Extremely Poor)
  3. Fan Speed (Number 0 - 100)
  4. Fan Mode (Number 0 = Off, 1-3 Manual modes, 5 = Auto…I don’t know what happened to 4, it’s a mystery)

I don’t really need the WiFi connection, but I would like the other 3 to be represented all in one widget. After Linking Items to those channels, I’m ready and I’ve got two initial decisions to make about how I add those Items to a widget: 1) How do I want each of those items to be rendered, 2) How to I want them arranged on my widget? Let’s start with question #1.

If you are not familiar with all options available, there’s an OH Component Reference page which takes you through them and shows examples. In this case, I’ve got some pretty simple choices.

  1. Air quality: This is just a measurement. I don’t need to interact with this Item at all, I just need to see the word telling me the current status. In widgets, displaying a simple word can be done in a few different ways. Two of the basic ways are with Label and Content components. If you are interested in the technical details you can find them here, but what that technical description boils down to is this:
    • A Label component can go just about anywhere, but is nothing but plain old text and you can expect to have to add all the special style and spacing yourself (we’ll get there, but not yet).
    • A Content component just places the text inside of something else that might already have the style and spacing. So, for basic needs, that can be easier in simple situations.

I expect I’ll want a Content for this basic (mostly) style-free widget.

  1. Fan speed: This is a number I need to be able to adjust between 0 and 100. There are a few different options here. Perhaps the most familiar is just the range slider, but steppers (up and down buttons) also let us change numbers, the knob or curved slider is also an option, as is a box where I could just enter the number manually. The stepper seems like a poor choice for a full 0 - 100 range unless I set pretty big steps and the manual entry too much of a hassle on some screens. The slider takes up a lot of room and I want several other pieces on the widget too. So, I’m going to opt to use the knob for this one.

  2. Fan mode: This is a number item, true, but it really is just a selection of a few preset options. I could make a list of those options and choose each one as needed, but again, that sounds like it takes up a lot of space on a widget. So, I’m going to use a button that when pressed presents the list of options separately.

Question #2 about how I want to arrange these pieces can often be addressed by making some quick sketches or mock-ups to get an idea. I know the Content and the oh-button are small and text-shaped (rectangular). The oh-knob takes up more of a square space. Let’s look at some options:

There’s no right answer here, all would work. Personally, however, I like option 2 the best. It keeps the two interactive elements (the button and the knob) spaced out a little to prevent clumsy me accidentally pressing one or the other. I also just find the horizontal layout a little cleaner.

I think I’m ready to start, so it’s time to head to the widget editor.

:memo: A Few Notes about YAML

YAML is a data serialization language. This is a fancy way of saying that the goal of YAML is to find a sweet-spot where humans can easily type and read something that computers can also easily convert into understandable data. You don’t need to be a YAML guru to work with YAML in OH, but, I find that thinking about it as a data structure does help. A few simple guidelines should get us where we need to be to work with the widget yaml in the editor:

  1. The basic building block is the key: value pair where key is the name of the data object and value is the data itself.
  2. Rule #1 means that there must always be a : in a yaml line (and there can only be one colon that is not part of other text).
  3. If the data is simple (text or a number) then the data just follows the colon (color: red).
  4. If the data is complex (multi-part object or a list), the colon will end that line and the next line will be indented one level to denote the start of the complex data.
  5. From #4 it becomes clear that indents are part of the structure - things indented the same amount are generally grouped together as a combined data object (each line starts with a key) or a basic list (each line starts with a -).

I’m not going to spend too much time with the top of the default text in widget editor for now. First things first, I always change the generated UID to something more meaningful (I’ll opt for demo_basic_widget here). I’m also not going to be using any widget parameters in this widget so I’ll replace the default list with an empty list (not required, but it does clean up the yaml a little). Beyond that we can skip right down to the first place where it says: component: f7-card. Now it’s time to start building the actual structure of the widget, starting with this root element.

2. The F7 Library

I mentioned up above all the OH specific widget components that are named oh-[something]. Now we see that the default configuration for a custom widget starts with a component that begins with f7- instead. MainUI is built using Framework7 (F7), a library of UI components with a baked-in, consistent style and easy to access functionality. After the OH widget docs, the F7 help docs are probably the next most common reference you will need when getting started. The first thing you will probably use the F7 docs for is just looking at examples of the components. At the bottom of each of the component help pages you will find two things: a scary looking block of code which you can ignore for now (that’s for the next tutorial), and a set of examples of the range of what that component will do which is helpful right now. So, I’ll check out the page for the f7-card, and looking at those examples, I think that the card will work nicely for my widget.

:double_exclamation_mark: OH vs F7 Components

With a few exceptions, the OH components are just built directly from the F7 versions. The OH reference docs show you examples of many of those components with OH specific styles already added on. The most important difference, however, is that the F7 components cannot interact with OH entities such as Items.

Do you need a toggle that controls a Switch Item? You will have to use the oh-toggle for that because the f7-toggle does not have the underlying code to communicate with OH.

So, for many of the truly interactive parts of your widgets, you will find you have to use the oh- versions of the components, but for basic structure and organization, the f7- components will make it easy to quickly create something that matches the rest of MainUI in style.

The f7 components that will do the heavy lifting for you when structuring a widget are the block, the row, and the col. The f7-block is really intended to be what you use to present a standard block of text area, but functions just as well as a generic region of a widget and the f7-row and f7-col are often used together to get a pretty easy grid-like layout.

There are a few other specialized f7 structure components you might use as well. In this case, for example, because I’m using an f7 card, there are some structure components listed on the f7 card help page for the cards header, footer, and content areas. I’m not going to customize the header or the footer, but I am going to use an f7-card-content component to get the first level of basic style and spacing for the things I’m adding to the card’s content area.

3. Keep It Simple

If you look at the underlying html of a modern web page, it feels like there are 20 extra html steps for every one that seems to be actually visible on a page. Assuming it is a well designed page, then each one of those pieces should be doing one thing and the designers should be able to articulate that purpose: “this one groups all the dynamic information that needs to be displayed incoming or out going”, “inside the main group, that one groups all the incoming information”, “inside the main group, that one groups all the outgoing information”, etc.
The same should be true for an OH widget. You should really be able to look at each component and say what’s its specific function is: “I included this to…”. If you can’t say what it’s doing, you probably don’t need it. One good way make this a part of your widget design is to work backwards from your idea and articulate what you need first.

For my widget then I need to see if I can articulate how the layout I sketched fits the three main f7 layout components:

  1. I explicitly defined “Air quality” as content to go in some block of text: this will now clearly be an f7-block
  2. I want that f7-block to be in a column with the mode button
  3. I want that two part column to be in a row with with knob
  4. I want that overall row to be in the content area of a card

We could do the same logic visually by drawing the structure we want right on our mock up:

In both cases what we can see here is that there’s no reason to over-complicate the structure. One of the reasons that UI library like F7 exist is that it can get pretty easy to get lost in the weeds of element position and spacing when building a web page. The f7 components are specifically designed to handle a lot of that work for you so it’s best to just let them do their job. There’s a very good chance this won’t be 100% perfect on the first try, but it’s going to be very close and will mostly like require minimal manual tweaking.

So, here’s my first attempt at the widget code:

uid: demo_basic_widget
tags: []
props:
  parameters: []
  parameterGroups: []
component: f7-card
config:
  title: Air Purifier
slots:
  default:
    - component: f7-card-content
      slots:
        default:
          - component: f7-row
            slots:
              default:
                - component: f7-col
                  slots:
                    default:
                      - component: f7-block
                        slots:
                          default:
                            - component: Content
                              config:
                                text: Air quality
                      - component: oh-button
                        config:
                          text: Fan mode
                - component: oh-knob
(Here's the same code fully annotated)
# Always give your widgets clear UIDs
uid: demo_basic_widget

# Tags do not impact the function a widget but can be used for
# filtering in the widget list page
tags: []

# Widget props will be covered in the advanced tutorial so we'll ignore them here
props:
  # Because we don't need any props we can set the parameters to an empty list
  parameters: []
  # This is empty by default but would be used if we needed to organize
  # many parameters
  parameterGroups: []

# Our root component. There can only be one root component.
# Note this does not start with a '-' it is a property in the main widget
# data object.
component: f7-card

# The data object containing all the configurations specific to our root component
config:
  title: Air Purifier

# Slots are how we put some components inside other components.
# All additional components must be inside the root component, so
# we use the root component's slots
slots:

  # Some components have multiple different slots (e.g., 'header' or 'footer').
  # 9 out of 10 times you just need the default slot. The help docs for the
  # f7 components will tell you if there are other named slots available beyond
  # just default.
  default:

    # Each slot will contain a list of components (note the '-' in front of
    # 'component'). This component is the container for all the content
    # we are adding to our card.
    - component: f7-card-content
      slots:
        default:

          # Inside the content container is our row container for the
          # column and the knob.
          - component: f7-row
            slots:
              default:

                # Inside the row container is our column container for the
                # block and the button.
                - component: f7-col
                  slots:
                    default:

                      # The block is only for holding the `Air quality` content.
                      - component: f7-block
                        slots:
                          default:
                            - component: Content
                              config:
                                text: Air quality
                      - component: oh-button
                        config:
                          text: Fan mode
                # The indentation of the knob matches the column
                # container because they are both part of the same
                # list; the children of the row container.
                - component: oh-knob

And this is the result:

Yeah, by keeping it simple we got pretty close!

4. The Finishing Details

I see only a few things I want to tweak to get it closer to my original idea:

  1. I want the button to be a little more obviously a button.
  2. The knob is a little too big relative to everything else.
  3. The “Air quality” text needs to be a little bigger, centered over the button.
  4. The button and the text need a little more space between them.

Let’s start with the button. The first place to look for properties of the button that can be configured is the oh-button reference page. I like the look of the raised button example on that page and if I scroll down through the properties I find that raised is just a boolean property so I’m going to add raised: true to my button config.

Same process for the knob. When I check the reference page for the knob I see a size property. I’ll start with 100 as a size and may adjust it later. I also like the look of the rounded ends I see in the examples on that page so I’ll add lineCap: round to the knob too.

Customizing the “Air quality” text is where we run into our first need for some direct changes to the style of a component. I said at the top that we need to know almost no CSS for basic widgets like these. We certainly don’t need to know any of the intricate details, or even much of the formatting. I’d say that right now we need to know 2 things:

  1. To change the appearance of any piece of a web page we can apply directives to the style attribute of that piece.
  2. There are a lot of different style directives and it’s not worth your time trying to remember them all (I sure don’t). So, find a CSS style reference page that you like (my personal go-to reference is w3 schools CSS reference, but there are many good options) or ask your favorite search engine. Even your friendly AI helper should be 99.9% reliable when asked a basic question like, “what’s the css to center text?”.

I’ll stick with my reference doc. I’m trying to change some text, so I’ll type “text” into the search bar above the style list in my reference page and the first filtered result says:

text-align: Specifies the horizontal alignment of text

That sounds just about right, and clicking on the link takes me to a description of the text-align style. Turns out I need text-align: center.

I don’t see any text results about size, so I’ll change the search filter to “font” and there’s

font-size: Specifies the font size of text

Perfect. I’ll pick a random gut feeling size for the font and then we can adjust it once we see the effect.

To apply these to a widget component I’ll add a style object to that component’s config object. The key: value pairs inside that style object will just consist of the style name for the key and the style value for the value. There’s one extra wrinkle in this case: the content component is one of the few widget components that doesn’t take a style object (because it’s just text and not an actual HTML entity); instead the style will be applied to the block that contains that content.

- component: f7-block
  config:
    style:
      font-size: 20px
      text-align: center
  slots:
    default:
      - component: Content
        config:
          text: Air quality

The spacing between elements on a web page is also handled by their styles. The most direct way to add space is the margin style which controls space outside the border of an element. To get space between the text and the button I could either add a margin below the text or above the button. Because I already have a style object for the text block, I’m just going to add the margin there and because I want it to be space below the text block, I’ll make it margin-bottom.

Click here for the full current widget text
uid: demo_basic_widget
tags: []
props:
  parameters: []
  parameterGroups: []
timestamp: Nov 14, 2025, 10:35:22 PM
component: f7-card
config:
  title: Air Purifier
slots:
  default:
    - component: f7-card-content
      slots:
        default:
          - component: f7-row
            slots:
              default:
                - component: f7-col
                  slots:
                    default:
                      - component: f7-block
                        config:
                          style:
                            font-size: 20px
                            text-align: center
                            margin-bottom: 20px
                        slots:
                          default:
                            - component: Content
                              config:
                                text: Air quality
                      - component: oh-button
                        config:
                          raised: true
                          text: Fan mode
                - component: oh-knob
                  config:                    
                    lineCap: round
                    size: 100

And here’s the result:

That’s good enough for me! Now that it looks right, we have to make it do something.

5. How do I make it do stuff?

This part’s usually pretty easy and there are three main ways you are going to have widget components interact with OH:

  1. Direct configuration - some oh- components connect directly to OH Items and then changes in the widget are directly sent to the Item and changes in the Item are immediately reflected in the widget.
  2. Widget action - other oh- components accept configurations that set up a widget action, that is, some OH activity that is preformed when the user interacts (usually clicking on) with the widget. This can include action that change Items, but many other actions as well.
  3. Widget expressions - Most places in the widget yaml, instead of a static value you can set the value to a dynamic expression which, if it includes information about an Item will update in real time as that Item changes.

The oh-knob is an example of the first type of OH interaction. This component has an item property and that property should be set to the name of an OH Item. I’ll add item: Filter_MasterBedroom_FanSpeed to the knob’s config object, and that’s all I need to do.
This type of configuration is two-way. The component both reads (and displays the current state of the Item) and can send commands to the Item as well to change the Item’s state.

The oh-button is an example of the second kind of interaction, the widget actions. In fact, these two are so closely linked, that the main reference information for the widget actions is part of the oh-button component reference page. When you look at those examples you see that the pattern is always the same; configuring an action requires setting the action property to the type of action you want and then configuring some number of additional properties that vary depending on the type of action. My fan mode item as described above is a series of options, so the action that makes the most sense here is the options action. Opening up the example on the actions reference page, I see that the options action will need actionItem and (optionally) actionOptions properties. Those are all separate config options so that looks like this for my button:

- component: oh-button
  config:
    raised: true
    text: Fan mode
    action: options
    actionItem: Filter_MasterBedroom_FanMode
    actionOptions: 0=Off,1=Low,2=Medium,3=High,5=Auto

Now, when I press the button my widget presents me with a pre-formatted list of options which will send the associated command to my fan mode Item.

The third kind of interaction, the widget expression, is required for the “Air quality” indicator (which at the moment is just static text). This is not the place to go over all the many things that widget expressions can do; there’s a comprehensive doc page for that. For now, I’m just going to focus on the most fundamental thing that a widget expression can do: give you access to some basic information about an Item.

All widget expressions begin with = and include syntax that parallels javascript. Right now you don’t have to know any javascript at all, because we’re just going to use an OH specific shortcut that always gives the State of the Item formatted how you’ve defined it in the Item’s state description metadata: @'Filter_MasterBedroom_AirQuality' (you can look in the link above to see exactly what this shortcut is doing).

Here’s the current state of the widget with the components all connected properly to OH.

Full widget code with actions
uid: demo_basic_widget
tags: []
props:
  parameters: []
  parameterGroups: []
timestamp: Nov 14, 2025, 10:35:22 PM
component: f7-card
config:
  title: Air Purifier
slots:
  default:
    - component: f7-card-content
      slots:
        default:
          - component: f7-row
            slots:
              default:
                - component: f7-col
                  slots:
                    default:
                      - component: f7-block
                        config:
                          style:
                            font-size: 20px
                            text-align: center
                            margin-bottom: 20px
                        slots:
                          default:
                            - component: Content
                              config:
                                text: =@'Filter_MasterBedroom_AirQuality'
                      - component: oh-button
                        config:
                          raised: true
                          text: Fan mode
                          action: options
                          actionItem: Filter_MasterBedroom_FanMode
                          actionOptions: 0=Off,1=Low,2=Medium,3=High,5=Auto
                - component: oh-knob
                  config:
                    item: Filter_MasterBedroom_FanSpeed
                    lineCap: round
                    size: 100

6. Can I change the color?

I want add one final touch to this widget that combines some of the pieces we’ve used up to this point. The black text for the air quality is a little dull. I think the color of the text should also reflect the scale of the air quality from “Poor” to “Good”? The widget expressions that I used up above can help here to, but first I need to know what property I have to use to set the color of that text. I know it can’t be a property of the content component (there are none other than text). I know some F7 components have text color properties so I check the F7 block help page, but I find no mention of a property for text color there either. If I go one step further up the widget tree to the column component, then any changes I make might also impact the button, which I don’t want. So, I’ve ruled out other options and now I know I have to use the block’s style object again and change the text color with a CSS property.

A quick search tells me that the CSS property for controlling the color of text is, conveniently, just color, and my helpful CSS reference tells me that color can accept a wide variety of formats to designate specific colors, including just using predefined color names. W3Schools has more than just CSS reference material and, in fact, there’s a page for all the predefined html colors you can use. To make this work in the widget, all I need to do is pick a color name and use that as the value for a color key in the block’s style object. For example:

- component: f7-block
  config:
    style:
      font-size: 20px
      text-align: center
      margin-bottom: 20px
      color: CornflowerBlue

image

But how do I use a widget expression to select a different color for each value of my air quality Item? This sounds like an advanced expression, but fortunately the OH expression doc page has a perfect example that I can adapt easily under the objects section. I just need to pick 6 different color names, and use them and the air quality text options to build a object in the expression and then reference the object with the current state of my air quality item.

- component: f7-block
  config:
    style:
      font-size: 20px
      text-align: center
      margin-bottom: 20px
      color: =({'Extremely Poor':'FireBrick','Very Poor':'DarkOrange',Poor:'Gold',Moderate:'YellowGreen',Fair:'GreenYellow',Good:'ForestGreen'})[@'Fitler_MasterBedroom_AirQuality'] || 'Black'
  slots:
    default:
      - component: Content
        config:
          text: =@'Filter_MasterBedroom_AirQuality'
GoodModerateExtremely Poor

I think that makes this widget complete! Thank you for reading this far. There’s plenty more to learn, if you are interested…

Next up: How To Build An Advanced Custom Widget

Resources In this Tutorial

OH Help Docs
Component ReferenceA list of the OH specific widget components, and the properties that can be configured
Creating personal widgetsIntroduction to the technical details of widget creation and the types of components available
Widget Action ExamplesDetailed descriptions and yaml configuration examples for the different OH actions
Widget ExpressionsDetailed look at widget expressions and the types of information available in the widget expression context
F7 Help Docs
F7 Vue ReferenceA list of the F7 components available to a vue-based app (such as openHAB) and their configuration properties
Other Resources
CSS ReferenceA list of the CSS style options as well their basic use in addition to more advanced CSS topics
HTML Color ChartA list of the regcognized named color for use in HTML and CSS
25 Likes

Thank you so much, what a fantastic tutorial!

An excellent tutorial. It covers everything I hoped it would and I think it positions the users much better in knowing the structure of a widget and how to use the docs. I’ve a few relatively minor comments and suggestions.

It might be worth warning not to worry too much about the HTML in the examples on that page yet. Pay attention to the components, properties, and appearance of the examples to start. Some users might panic when they see all that HTML in the examples.

My first thought what “where the heck did f7-card-content come from?” Going back to the f7-card reference I see is listed under “content” along with a header, footer and such. Searching the page shows it has one property, “padding”.

It might be worth a sentence explaining this, so users are not surprised with the sudden appearance of f7-card-content and are given a little more context about how to learn more about it.

This is the fist time these keywords appear and there is no explanation.

I hate to make the tutorial longer, but it feels wrong to not even mention these in passing before they appear.

Maybe it’s worth a sidebar like you did with YAML explaining the overall YAML structure of components:

component: component-name
config:
  property: value
style:
  css-property: value
slots:
  default:
    - component ...

You’ve already explained the hierarchy, but the structure just appears here.

Since you don’t use the props, you should probably remove them from these examples until ready to introduce the concept.

For consistency, we should link to that page too here.

The same would go for label, too right?

This paragraph is golden. It’s a perfect example of what I hoped to see. The reasoning and what one does to find the right reference. The false trail looking at the F7 block properties is perfect. Users won’t always know what they need and where they look first and this shows them what to do. I love it!

A most excellent tutorial!

3 Likes

Excellent work…thanks so much for taking the time to do this!

My question is around the decision to create a custom widget, and to use it.

I use MainUI with the Semantic Model so my access to Devices is a collection of Rooms containing Items.

For me (and I suspect many others) adding a new device means creating some Items in a Room and using whatever the MainUI gives me by default.

I understand Custom Widgets are a more efficient way of grouping a few Items and more aesthetically pleasing, but how would I use them in the Model/Location card environment?

I have applied some custom widget properties to some Items by revising Metadata, but only on an Item-by-Item basis.

Could I use your custom Air Purifier widget in an automatically created Location card? If so, how?

Maybe this is described in the docs but for me it’s not obvious.

Yes. You would set the “Default List Item Widget” metadata on the semantically tagged and Grouped Item. That will be used by default instead of whatever OH guesses would be the best widget.

If you create a widget that combines multiple Items from the same device into one, like shown here, my recommendation is as follows:

  1. create the custom widget from Developer Tools → Widgets.
  2. pick one of the Items from the Equipment and set the “Default List Item Widget” metadata on that one Item to the widget created in 1
  3. modify the Default List Item Widget metadata for the rest of the Items in the Equipment by setting the visibility to false.
  4. Repeat 2-3 for each Equipment.

Note however that the widget presented above is not a list item widget. You need to use different types of “containers” for list Item widgets. I hope this will be covered in one of the subsequent tutorials.

Here is an example of a simple list Item widget that combines multiple Items:

uid: rlk_garagedoor_list
tags:
  - garagedoor
  - list
  - marketplace:126585
props:
  parameters:
    - description: Door name
      label: Name
      name: name
      required: false
      type: TEXT
    - context: item
      description: Control Item
      label: Control Item
      name: control_item
      required: false
      type: TEXT
    - context: item
      description: Sensor Item
      label: Sensor Item
      name: sensor_item
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Feb 3, 2021, 1:12:37 PM
component: oh-list-item
config:
  action: command
  actionCommand: true
  actionItem: =props.control_item
  badge: '=(items[props.sensor_item].state == "CLOSED") ? "closed" : "open"'
  badgeColor: '=(items[props.sensor_item].state == "CLOSED") ? "green" : "red"'
  icon: '=(items[props.sensor_item].state == "CLOSED") ? "f7:house" :
    "f7:house_fill"'
  iconColor: '=(items[props.sensor_item].state == "CLOSED") ? "green" : "red"'
  title: =props.name

image

Notice how the root component is an oh-list-item.

If you decide to change things later, by following the approach above, you only need to edit the widget under Developer Tools → Widgets and your changes will apply to all the places where that widget is used (i.e. you only need to edit the widget in that one place) once MainUI is refreshed. So I recommend this approach even for very minor customizations to widgets (e.g. just changed the icon). That way if you decide later you want to use a different icon for all your light switches (for example) you need only make a change in one place and it will apply everywhere.

See Pages - Item Widgets | openHAB which mentions this but probably could be improved. Or it might be that these tutorials replace or augment what’s in Getting Started.

That’s a good point. I definitely intend to start linking the code on those pages to the widget yaml in the next tutorial, but I’ll flag it as something not to worry about for now.

I tried to allude to it, but I guess my first attempt was too obscure. I’ve expanded on that now.

Ooh, that’s a really good point. I’ll have to think for a little bit about the best way to add this in without doubling the length of that section…

I went back and forth on this a couple of times and couldn’t make up my mind since they can also just be ignored. I’m glad someone else has an opinion.

No, that’s actually the basic difference between the Label and the Content components. You can add classes and styles to the labels and those impact just the text in the label directly. That’s basically what’s in the “technical details” that I allude to with the link when I introduce those two at the top.

In the end,

- component: Label
  config:
    class:
      - my-text-class
    text: Some text here

and

- component: div
  config:
    class:
      - my-text-class
  slots:
    default:
      - component: Content
        config:
          text: Some text here

would render into the exact same html. So, Content is an option just because sometimes a div element isn’t the actual element you want the text to be inside of, as in the case of the tutorial widget.

All of my day to day interaction stuff is accessible through widgets on my overview page with fewer clicks than going through the Model pages. I primarily use the model pages for debugging, for example, if I need to see all the different outputs of a sensor at once.

That said, Rich’s answer is pretty complete about adding custom widgets to the model and there are several places where I have done exactly as he’s described and added an equipment level custom widget that has all the items in one place when it makes sense to me.

Getting Started still has some important intro stuff that’s not covered here so I would argue for “augment” at most.

1 Like

I was waiting for the props to be discussed in the tutorial, so I second Rich’s opinion. :slight_smile:

You could make a different doc about it, and link to it here.

I added a completely annotated version of the first widget yaml. It’s collapsed by default, but if a reader has questions about the original yaml it can be expanded to explain most of the yaml widget structure.

Is that sufficient?

1 Like

Is this really true? I know that in the past, I couldn’t find an overview of this in the F7 docs. Even now, if I go into e.g the button docs, I can’t find any mention of slots.

I suppose I should be more precise. Slots are only listed on those pages for any f7 component that has named slots beyond just default. If you don’t see any listed then default is the only option.

That makes sense of a button, there is only inside the button or not. There are not “different specific areas” inside a button as there are with, say, a list item.

That’s a very crucial piece of information, and frankly one that F7 should provide. Since I’ve never seen a component where slots are documented, I don’t know what to look for, so I don’t know how to “be sure” that it only has the default slot. So, I still consider it crappy documentation - it wouldn’t cost them much to document just the default slot for the components that just have that.

These details are beyond the scope of this tutorial, but this is not the fault of the F7 documentation at all. As far as their system is concerned, the documentation is precise and accurate. This discrepancy comes from a combination of how html slot attributes work, openHAB’s attempt to make widget yaml fully consistent and generic, and f7’s use of slots in their components.

The full detail of my previous answer is that some f7 components have named slots and you can find those on the f7 docs page. For some f7 components that do have named slots, one of those slots can also be accessed by using the slot name default. That sets the precedence for default as a slot name. In order to make processing widget yaml easier and more consistent, every slots object must have at least one property. So, for objects that do not have a slot, the label default is still used. That extra default slot attribute on the html elements implied by MainUI in this way is safely ignored when not needed so it, for example, doesn’t interfere with the structure of f7 elements that do not have one or more slots.

So, this is really something imposed by MainUI artificially when no slot actually exists.. which makes me agree that it’s not the fault of F7, but it’s still frustrating to be told to find the slots in the F7 documentation and don’t find it mentioned at all. It could probably be amended to something like “if more than the default slot is available, they will be listed in the F7 docs”.

I changed the annotation comment to “The help docs for the f7 components will tell you if there are other named slots available beyond just default.” After you first pointed out that it wasn’t precisely correct.

1 Like

I certainly hope so. It’s much more thorough than I was thinking which is great! Collapsed is a good way to handle it.

this tutorial is amazing, was looking for something like this for months since i started with OH. many many thanks.

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.