OH 5: MainUI Widgets Best Practices

There is a lot of institutional knowledge here on the forum and in the docs, but I just spent a couple of days updating a couple of my widgets, and I’ve been struggling.

I’ve read through parts of a bunch of tutorials and documents and looked at many forum postings and looked at examples, but I still feel lost.

Should I be using f7-block, f7-row, and f7-col all the time?

Should I always use a block as the outermost container or could I start with a column or a row?

If yes, should there be only one widget at the bottom of the hierarchy?

Where do I go to find all the “classes” supported by these and maybe a little description of the behavior. For example, if I set a class “justification-content-center” on the f7-block, is it supposed to apply to everything in that block?

How do I make a widget that sizes its height based on the content of the widget instead of hard coding it?

What the heck does the display-flex class do, and when should I use it?

What are the defaults when I don’t set any classes or style to the blocks, rows and cols?

When should I use absolute positioning instead of relative?

The oh-X stuff seem very well documented and I never feel lost using them. But I don’t feel like I have a grasp of the overall proper way to use blocks, rows, and cols to build a widget that looks like I want yet resizes in meaningful ways. And when I follow the links in the docs or search online I feel like I’m dropped into the deep end of a vast pool of information and can’t seem to find what I’m looking for.

A concrete example might be worthwhile for discussion purposes.

There are warnings about not overly nesting the cols, rows and block because of performance, but what is too much? What’s the alternative?

I had an old widget that was pretty hard coded with lost of absolute positioning. I’ve recently tried to rewrite it using best practices, and I am not at all happy with the results.

Here’s the code.

uid: new_levot_humidifier_list
tags:
  - list
props:
  parameters:
    - default: Humidifier
      description: Set the title for this Humidifier
      label: Humidifier
      name: title
      required: false
      type: TEXT
    - context: item
      description: Parent Equipment Group representing the humidifier
      label: Equipment
      name: equ
      required: true
      type: TEXT
  parameterGroups: []
timestamp: Nov 6, 2025, 8:35:02 AM
component: f7-list-item-row
config: {}
slots:
  default:
    - component: oh-context
      config:
        constants:
          it:
            display: =props.equ+'_Display'
            empty: =props.equ+'_WaterLowEmpty'
            level: =props.equ+'_HumidityLevel'
            mist: =props.equ+'_MistLevel'
            mode: =props.equ+'_OperationMode'
            power: =props.equ+'_SwitchedOn'
            sp: =props.equ+'_HumiditySetPoint'
            warm: =props.equ+'_WarmLevel'
            warmOn: =props.equ+'_WarmModeEnabled'
        functions:
          color: "=(level) => (level > 45) ? 'purple' : (level > 30) ? 'blue' : 'orange'"
      slots:
        default:
          - component: div
            config:
              class:
                - card
                - card-content-padding
              style:
                boarder-radius: var(--f7-card-expandable-board-radius)
                height: 155px
                noShadow: true
                width: 100%
            slots:
              default:
                - component: f7-block
                  slots:
                    default:
                      - component: f7-row
                        config:
                          class:
                            - justify-content-center
                            - align-items-start
                        slots:
                          default:
                            - component: f7-col
                              config:
                                class:
                                  - align-items-start
                              slots:
                                default:
                                  - component: f7-icon
                                    config:
                                      color: =fn.color(#const.it["level"])
                                      f7: drop
                                      size: 20
                            - component: f7-col
                              slots:
                                default:
                                  - component: Label
                                    config:
                                      style:
                                        color: =fn.color(#const.it["level"])
                                        font-size: 14px
                                        font-weight: 700
                                        margin-top: 0px
                                        width: 200px
                                      text: "=(@@const.it['power'] == 'OFF') ? 'Humidifier is off' : props.title + '
                                        is set to ' + @@const.it['sp']"
                            - component: f7-col
                              config:
                                class:
                                  - align-items-end
                              slots:
                                default:
                                  - component: f7-chip
                                    config:
                                      style:
                                        --f7-chip-bg-color: rgba(255, 255, 255, 0)
                                        color: =fn.color(#const.it['level'])
                                        font-size: 14px
                                        position: absolute
                                        right: 0px
                                        top: 0px
                                        width: 12%
                                      text: =@@const.it['level']
                      - component: f7-row
                        slots:
                          default:
                            - component: f7-col
                              config:
                                style:
                                  width: 100%
                              slots:
                                default:
                                  - component: oh-slider
                                    config:
                                      color: =fn.color(#const.it["level"])
                                      item: =const.it['sp']
                                      label: true
                                      max: 80
                                      min: 20
                                      releaseOnly: true
                                      step: 1
                                      style:
                                        top: px
                                        width: 100%
                                      unit: "%"
                      - component: f7-row
                        slots:
                          default:
                            - component: f7-col
                              slots:
                                default:
                                  - component: f7-row
                                    config:
                                      class:
                                        - justify-content-center
                                        - align-items-center
                                    slots:
                                      default:
                                        - component: oh-knob
                                          config:
                                            item: =const.it['mist']
                                            max: 3
                                            min: 0
                                            size: 80
                                            stepSize: 1
                                            style:
                                              color: =fn.color(#const.it["level"])
                                            textColor: =fn.color(#const.it["level"])
                                  - component: f7-row
                                    config:
                                      class:
                                        - justify-content-center
                                        - align-items-start
                                    slots:
                                      default:
                                        - component: Label
                                          config:
                                            class:
                                              - justify-content-center
                                            style:
                                              color: =fn.color(#const.it["level"])
                                              font-size: 10px
                                              font-weight: 500
                                            text: Mist Level
                                            unit: "%"
                            - component: f7-col
                              slots:
                                default:
                                  - component: f7-row
                                    config:
                                      class:
                                        - justify-content-center
                                        - align-items-center
                                    slots:
                                      default:
                                        - component: oh-knob
                                          config:
                                            item: =const.it['warm']
                                            max: 3
                                            min: 0
                                            primaryColor: orange
                                            size: 80
                                            stepSize: 1
                                            style:
                                              color: orange
                                            textColor: orange
                                  - component: f7-row
                                    config:
                                      class:
                                        - justify-content-center
                                        - align-items-center
                                    slots:
                                      default:
                                        - component: Label
                                          config:
                                            style:
                                              color: orange
                                              font-size: 10px
                                              font-weight: 500
                                            text: Warm Mode
                            - component: f7-col
                              slots:
                                default:
                                  - component: Label
                                    config:
                                      style:
                                        color: "=(@const.it['empty'] == 'ON') ? 'red' : fn.color(#const.it['level'])"
                                        font-size: 14px
                                        font-weight: 700
                                      text: "=(@const.it['empty'] == 'ON') ? 'Water: empty' : 'Water: ok'"
                                  - component: Label
                                    config:
                                      style:
                                        color: =fn.color(#const.it["level"])
                                        font-size: 14px
                                        font-weight: 700
                                      text: "='Mode: ' + @@const.it['mode']"
                            - component: f7-col
                              config:
                                class:
                                  - align-items-end
                              slots:
                                default:
                                  - component: f7-row
                                    config:
                                      class:
                                        - align-items-end
                                    slots:
                                      default:
                                        - component: f7-col
                                          config:
                                            class:
                                              - align-items-end
                                          slots:
                                            default:
                                              - component: Label
                                                config:
                                                  style:
                                                    color: =fn.color(#const.it["level"])
                                                    font-size: 14px
                                                    font-weight: 700
                                                  text: Power
                                        - component: f7-col
                                          config:
                                            class:
                                              - align-items-end
                                          slots:
                                            default:
                                              - component: oh-toggle
                                                config:
                                                  item: =const.it['power']
                                                  color: =fn.color(#const.it["level"])
                                                  fill: true
                                  - component: f7-row
                                    config:
                                      class:
                                        - align-items-end
                                    slots:
                                      default:
                                        - component: f7-col
                                          config:
                                            class:
                                              - align-items-end
                                          slots:
                                            default:
                                              - component: Label
                                                config:
                                                  style:
                                                    color: =fn.color(#const.it["level"])
                                                    font-size: 14px
                                                    font-weight: 700
                                                  text: Display
                                        - component: f7-col
                                          config:
                                            class:
                                              - align-items-end
                                          slots:
                                            default:
                                              - component: oh-toggle
                                                config:
                                                  item: =const.it['display']
                                                  color: =fn.color(#const.it["level"])
                                                  fill: true

What I don’t like and haven’t figured out how to address:

  • How do I get rid of that space at the top? Alternatively, how do I set the block title if I can’t get rid of that space?
  • Can I get the icon all the way to the left so it lines up with the start of the slider?
  • Same for the percent in the upper right.
  • I want the two arcs to remain close together pinned to the left when it resizes and the label and toggles to stay together at the right when the widget resizes. But everything spreads apart.

  • This widget doesn’t seem to display consistently on the pages. I think it has to do with the hard coded height. How do I make it consistent? I had to make the height larger than necessary to keep the bottom of the second widget from overflowing into the widget below it. This may be a more specific question since this is an odd widget being used in a list card.

I feel like I’m really close to having a good understanding and then when I try to apply my understanding, either things don’t change at all or change in unexpected ways which shows I don’t really understand.

Any advice for MainUI Widget experts would be most welcome. I’m not necessarily looking to fix this specific widget as much as I am looking for understanding which I can apply to my other widgets and helping on the forum going forward.

11 Likes

I’ll do my best, but no promises.

I think part of what’s driving the issue with the docs and general information about the widget system how expansive it has become. @ysc gave us an amazing base system with his work building the MainUI for OH3, but it has blossomed into so much more since then. And now what a user feels like should be a simple question very rapidly runs into a gray area where the discussion moves from OH specific details and ideas briefly through the underlying f7 library and then before you know it you’re into full on web dev.

That said, despite having somehow landed in the position of one of the OH MainUI experts (I’m still not sure how this happened), I’m no web dev. I teach at a medical school. I’ve been hobbying computers since you had to put the OS 5.25" disc into drive A and the Application 5.25" into drive B (what’s a C: drive?). I’ve been scripting since the Basic compiler on my old TI-99. But, I have exactly 0 minutes formal education in any of this. So, I make no claim at all that my recommendations are best practices; but these are my practices and the things I’ve learned from trial and error and many hours of feeding my curiosity and urge to tinker.

This is actually a good question to start with. My answer: I don’t.

I never attempt widget creation without the browser dev tools elements tab open and make extensive use of the inspection function. Going beyond the very basic steps of widget creation it really is important to see past the components to the html:

When you do this, it becomes clear that blocks rows and cols are just the most basic of div elements each with a single f7 class added to them:

Widget yamlResultant html
component: f7-block
config:
  id: block1
slots:
  default:
    - component: f7-row
      config:
        id: row1
      slots:
        default:
          - component: f7-col
            config:
              id: col1
<div class="block" id="block1">
  <div class="row" slot="default" id="row1">
    <div class="col" slot="default" id="col1">
    </div>
  </div>
</div>

It’s those classes, of course, where the the problems occur. F7 does a lot under the hood. Here’s a list of the f7-block specific css variables, and that’s just the ones they expect you to want to change. All this extra work done for you is what makes it such a good tool, but also where most of the “black-box” nature of the widget system comes from. F7 uses those base component classes not just to apply css styles, but to identify the elements targeted by each of it’s many scripts.

So, when do I use blocks and rows and cols? Only when that component is about matching the style and spacing of the UI. If it’s about having better fine control of the child elements, then I’ll often just use a div instead because I don’t want all that other stuff.

Here’s an example. I have a widget I’ve created to match the style of MainUI configuration detail pages so I can display some of my more complex personal systems in a consistent way:

This widget extensively uses blocks and rows because those are how the MainUI page itself is built. But my timed confirm button uses only div elements for its structure.

The warning about performance with the overuse of blocks, rows, and cols, also comes from that F7 under-the-hood stuff and the many scripts it runs to modify nearly every F7 component, but to be honest I have never seen much of an issue except maybe the tiniest of slowdowns on the very oldest of devices.

Again, I don’t always. On the other hand, that root component is where a lot of the base css (either in a style object or in a stylesheet) is going to go so it does often make sense to have some basic container (either a block or a div) as the root. An f7-card and all of its oh derivatives also start with just a div but it’s a div with even more styling and scripting than a block so that’s why cards also make good root components.

The block feels to me like it comes with the least baggage, so it’s a good default choice , but there are plenty of reasons why you may want to use one of the others. If you know that from the start your widget is going to have a vertical layout, maybe the col is a better root component.

There are very few places where MainUI puts any restrictions on what you can and can’t do. There are a handful of examples, e.g., an oh-grid-col in the block section of a layout page will not render more than the first child component, but they are few and far between. The system could, probably, have more safeguards in that respect but html, in general is so flexible and robust, that it’s pretty difficult to break things, you just get widget that don’t look like you where expecting and don’t do what you wan them to.

Finally, an easy one!

Those classes all come from F7 and are listed in the docs page intuitively titled ‘Typography’:

This is, however, an excellent example of what I said at the start. This should be a fairly straightforward question for a user just starting out with widgets, but…

All these classes do is give you a kinda-maybe-sorta shortcut to applying the css variable of that name. So, the answer to whether a class impacts the component or the component and all its children depends on which css property you are dealing with. So now, you really need to starting thinking about css inheritance rules and which properties are inherited and which are non-inherited. The good news is, if I recall, most of the properties that are tied to these F7 classes are non-inherited so if you apply the class to a component, it will only impact that component.

I never use these classes myself. Because the OH widget syntax gives you such easy access to most basic css through the style object there’s simply no benefit to doing this through the slightly more opaque F7 classes.

Well, so much for easy questions…

I would bet that there are more pages on the internet about this one topic than there are threads in this entire forum. Here we’ve gone fully past any grey area and are simply talking straight up web dev. This sort of sizing will also be the most difficult part of just about any complex widget. I can make the most meager start at barely scratching the surface.

In an ideal world, this isn’t something you need to worry about. Most html elements, by default, will have a minimum size to encompass all their child elements (the default value for both width and height css properties is auto. No web page, however, is an ideal world, because the minute you are talking about a discrete page there are already constraints.

My first piece of advice in this sort of situation is always do as little as possible; get out of the way, just let html and css do their jobs, and see if that works. This will of course only get you so far because, you guessed it, all those F7 components are packing extra settings that are going to get in way. That’s when you then need to start thinking about applying you’re own width and height values. Which part (or more likely parts) are going to need those values may be difficult to determine. This is another situation where browser dev tools are very helpful. The css pane in the elements tab has a computed section which will give you a kind of visual outline of what the final css values are for each property and you can sometimes see what’s causing something to only be X pixels tall when you thought it should be Y. Or it will show you that there are no height or width values for this element and so it is just passively getting those from its children (what you presumably want in a case like this).

There are probably people out here who can look at a whole section of html and identify on the first try where a css size or position bottleneck is, but I’m not one of them. It usually takes me a couple of tries to find the right combination of tweaks. For all know that sort of trial and error is css best practice, but I doubt it.

Well from the previous answer, this just applies the flex value to the container’s display property. This means it turns the container into a flexbox. Flexbox and grid are two of the best ways to get responsive sizing and spacing in css, and will always be my two first choices when building a widget (although again, instead of using the display-flex class I’ll just add display: flex to the components style object.

In fact, you’re already using it quite a bit. One of the default css settings for the f7-row is display: flex;. It’s part of the answer to your specific questions below about you widget. One of the links I’ve probably posted the most over the years (and I know Yannick has posted several times as well) is a good basic introduction in what flexbox can do and how to use it.

Also on the F7 site, on an actually sensibly named page, you can find a list of all the default values for the f7 css variables: CSS variables. This doesn’t include the css directives that are set without variables (i.e., the things they don’t want you to be able to easily override). To my knowledge, those values you will just have to find using the dev tools.

In my opinion, almost never. I think I’ve even gone back at this point and changed any of my early widgets that did use absolute positions to relative positions. Even in situations where you are working around absolute things like bars or panels on a page, you are better off calculating a relative value from that absolute value (e.g., calc(100% - 32px)).

So applying all this to your example questions about the widget. Here’s my process:

The first thing I’m going to do is bust out the dev tools and see if I can identify that space:

That tells us it’s the top margin of the block element that is inside the card contents. So, first we check if we can override that the easy way:

- component: f7-block
  config:
    style:
      margin-top: 0

Success!

These are part of the same answer. Here you’ve over-used the f7-col and and f7 classes (and added some absolute positioning as well):

You want the children within this f7-row to stretch fully from end to end. With flexbox (which the f7-row is by default) the justify-content: center; css directive tells the flexbox to try and squeeze all the child elements as close to the center as possible. The only reason you don’t see them all adjacent is that you have put them in cols which adds a bunch of automatic size and spacing.

Following the philosophy of getting out of the way and letting the flexbox do the work, I recommend the following:

  1. Get rid of both the classes on the row: space-between is the default justification setting for the row and that’s what you want here and start is already the item align for the row as well.
  2. Get rid of all 3 cols: you have a precise idea where you want these child elements (fully left, center, and fully right) and you don’t want the cols making extra decisions on size and spacing that will interfere with that.
  3. Get rid of the top, right, and position style settings on the chip: any child elements with absolute positioning will ignore the position directives from the flexbox parent and you want the parent to set the position here.

Those changes result in:

This is just a basic web dev structure thing. Again, you’ve over engineered the row and columns when you just really need one container every time you want two or more things to share some organization:

  1. you want the power label and it’s toggle to remain side by side: sounds like a row → f7-row1
  2. you want the display label and it’s toggle to remain side by side: sounds like a row → f7-row2
  3. you want f7-row1 and f7-row2 to be stacked vertically: sounds like a column to me → f7-col1
  4. you want the water and mode labels to be stacked vertically: another column! → f7-col2
  5. you want f7-col1 and f7-col2 to remain side by side: another row → f7-row3
  6. you want knob1 and its label stacked vertically: column → f7-col3
  7. you want knob2 and its label stacked vertically: column → f7-col4
  8. you want f7-col3 and f7-col4 to remain side by side: another row → f7-row4
  9. you want f7-row3 and f7-row4 to be spaced automatically across the width of the card: flexbox time! → f7-row5

So that looks like this structure-wise:

f7-row (#5)
  f7-row (#4)
    f7-col (#4)
      knob
      label
    f7-col (#3)
      knob
      label
  f7-row (#3)
    f7-col (#2)
      label
      label
    f7-col (#1)
      f7-row (#2)
        label
        toggle
      f7-row (#1)
        label
        toggle

Here’s the result of that structure with absolutely no additional classes or setting on any of those rows or columns:

Pretty close! Looks like we just have a little bit of tweaking to do. I see two issues to start with:

  1. we want the knob labels centered: that’s easy to fix. The labels are already centered in the column (you can check dev tools to verify this) but the text isn’t centered in the labels, so we just add text-align: center to the label styles:
  2. The rows that hold the toggles and their labels shrank so much that flex box decided it was easier to split into two rows: also an easy fix. We can use flex-wrap: nowrap to tell those rows to always be only one row.

Almost there! The toggle + labels are a little off. We;d like some space between them and we don’t want the lower one to push beyond the edge of the card.

  1. The space issue is easy. Flexbox comes with a gap property that gives a consistent space between all children. So in this case well add gap: 5px to the styles of the rows that hold the toggles and their labels.
  2. the position of the lower row is a little trickier. Flexbox has made a poor choice about how to space and size it’s child columns. The basic answer is that we need the felx box to preserve a little more space for that last column. There are enough different flexboxes (f7-rows) in this structure that we have a couple of choices, but I think the most direct one is to tell the columns on the right side to be slightly different sizes. In this case we want the column holding all the toggle pieces to expand more than the column holding the simple labels. flex-grow is the css to determine what proportion of the available space a flex child item takes up (with the default being 1). So if we set that last column to flex-grow: 1.5 it’ll be a little larger and the toggles will fit.

Looks great! And is fully responsive to size:

Of course there are still many things we can continue to tweak until it’s perfect. Maybe you want more space between the water/mode labels and the toggles. Identify the correct row container and add a gap style. Maybe you want more space between the top row and the bottom row on the right side. gap works for flex columns too (just make sure you add it to both those columns)…etc.

*This is not the only structure that solves this arrangement. The right side could also be just one column with two rows and each row has two sub rows which hold a label and a label + toggle respectively. Or you could go with a css grid…or…etc.

I suspect, that once you’ve gone through and trimmed down the extra cols and rows and such you’ll find you don’t need the hard-coded height anymore. If I’m wrong, post a follow up and I can work through figuring that out too.

One last note: This is may be a slightly awkward time for this answer. Several people have done an amazing job in the last few months updating MainUI from Vue2 to Vue3 and, in fact, the newest snapshots at this point are on Vue3. This change should be fairly invisible for most users and will only impact the stuff here a little bit, but as I understand it, it is also a prelude to at some point moving OH to F7 version 8 from F7 version 7 and that could impact quite a bit (for example f7-rows and f7-cols don’t exist in version 8).

17 Likes

I was hoping you’d respond and this is really good content.

Did you have the audio cassette tape storage on the TI-99? Man I loved that machine. We even had the voice add-on module. I can still hear Spock saying “welcome aboard captain” when starting the Star Trek game. Unfortunately it broke around the time that we got our first Intel x286 (with the turbo button!) and I took it apart for a school project.

I have basically the same history only my first degree was in computer science so theoretically I am a programmer. But my front end experience ends at using GridBagLayout in Java 6. The only reason I know any JS at all is because of openHAB rules and I don’t know a <div> from a <p> in HTML, let alone anything to do with CSS. And it just seems like a lot to have to learn all at once which prompted my post. It felt unreasonable to expect most of our users to have to lear so much to build relatively simple custom widgets.

What tells us that? The fact that it’s colored orange instead of green or blue (are the margins color coded)? And once I do know it’s the margin, I can figure out how to change that by looking at the Typography link above, right?

And this begs another question, what the difference between a class and a style? You used margin-top in the style section of the config, but the Typography docs calls them classes so I would have expected to use them in the classes section based on that. Or is this a case where there’s a CSS style and an F7 class that have the same name?


Overall this kind of confirms my original suspicion. There is no big red easy button. One really can’t get by without knowing quite a bit about F7, CSS, and HTML.

But some best practices I pull from your reply are below. I think they can greatly help constrain the search space when needing to figure out how to do something. And even more importantly, they help provide an overall work flow to design the widget, build the initial widget, and then tweak it to make it as close to the end goal as possible. That’s very valuable and exactly what I was hoping to get from this post.

Rules of thumb:

  • get a background knowledge of HTML, CSS and F7

  • do as little as possible

  • use the browser dev tools (though of course understanding what you are seeing in those tools requires a bit background knowledge)

  • flex is the default layout, see CSS Flexbox Layout Guide | CSS-Tricks for how it works, use this instead of manually adding cols and rows where possible

  • avoid absolute positioning and use calculated values instead (is this CSS or F7? what can I pass to calc(), always a % ± px?

  • avoid the use of f7-col and f7-row except when trying to match something in MainUI’s look and feel. Use div for the simplest “container” but realize you’ll need to specify a lot of style stuff yourself that the f7-block/col/row do for you. Also f7-row and f7-col are going away soon (do we just use f7-block then? How do we make our widgets future proof or can we?).

  • figure out what needs to stick to what (e.g. a label with a toggle) and group those together in a row or col or block(?) or div(?) and build the widget on paper identifying all those groupings. Then build the hierarchy based on that structure. Key insight: if you have an f7-row, the columns are built for you. If you have an f7-col, the rows are built for you. You don’t need to specify both except when it’s meaningful (i.e. to combine multiple elements as one sub-widget)

Development work flow:

  1. draw a sketch
  2. find the groupings (e.g. labels and toggles go together as one sub-widget)
  3. build the hierarchy on paper
  4. using the hierarchy, build the initial widget using the minimum rows, cols, and blocks (or just use div) required
  5. adjust the flexbox settings to fix spacing and alignment issues; in some cases you may need to return to 2

Thank you very much! This reply is exactly what I was hoping to get! I’ll rebuild that widget, and we will see if this spark of understanding is real or not. :smiley:

3 Likes

I generally feel much is the same boat as @rlkoshak if I try to do some widget stuff. I have some ideas about how things work, but rarely enough to actually make them do what I want. Getting information is hard, it’s spread out all over the place, and it’s hard to know what to search for. The F7 documentation in general is terrible in my opinion. They usually list the “obvious” stuff and say nothing about the stuff I want to know. I’ve been extremely frustrated poking around at the F7 website at times.

So, what I generally have to do is to find something that looks somewhat like what I want, and then tweak that. Then, I can at least see what causes what, and progressively make it closer to what I want. But, it’s a slow and frustrating process.

It’s actually ironic, but I find it easier to make write MainUI than to make UI widgets. The YAML system does it’s part to make it awkward and unintuitive. There’s no way to “know” what’s missing or how the overall structure should be. It’s easy enough to change what’s there, but when it comes to knowing what slots are “valid” for a component, for example… I just find it a hopless task.

I’ve seen a lot of praise of F7 here, but personally, I pretty much dislike every part of it. It feels like it’s written by and for web developers, people that already know everything about HTML and CSS. For these, some things are taken care of that rid you of some of the “boilerplate work”, if you happen to “guess” what F7’s logic is. Don’t count on them explaining it. But, for people that don’t know HTML and CSS by heart, I think it’s close to useless. The distance beween “F7 world” and “full HTML/CSS” is very short, and the lines often blur.

So, I’d say that if you’re not familiar with HTML/CSS, the browser dev panel in pretty much useless to you, and you’re out of luck if you want to do anything that impacts layout. You can change what is shown without too much trouble, but you’d better just accept where it ends up, or be ready for a world of pain.

Personally I think layout in HTML/CSS has always been terrible. There is no “true relative” ways to make things, because you can’t use the same relative units on everything. Fonts, lines, borders etc. often don’t work with relative units. And the fact that they f.. it up so thorougly that “pixels” themselves are somewhat relative just underlines the failure. It’s amazing to me that we don’t have something better after all these years. “Reactive” is thrown around like any good buzzword, but in realty, very few things scale well.

But, enough of that. The problem here is that all these shortcomings are in reality not very far beneath the surface also for UI widgets, only that it’s worse. Because in a browser, you can “cheat” by throwing some JavaScript at it when things won’t behave, and do some calculations that way. You can’t in the UI widgets, so every time you’re bitten by something, you have few options.

I was quite fond of what could be made of with echarts in widgets, but I soon realized that this also suffers from the same fundamental problem: they don’t scale well. Sure, they scale, but you can’t move very far from the “design size” before things starts to break. Relative values just don’t work properly, some things scale from some awkward “origin” that makes it impossible for one value to fit different scales, fonts don’t scale and ditto with lines. All this just put me off UI widgets, it’s just too hard to get the layout part to work. Functionality-wise I think it’s quite flexible and useful, but there’s a limit to how much that helps when the layout is an eternal, unwinnable, struggle.

One of the few ways I can think of that could make creating UI widgets “more accessible” was if somebody made “a library” of widgets without content using different layouts, and then documented what the “layout rules” for that component is. By that, I mean, what it can and cannot do, when it is suitable and when it’s just a waste of time to start with. People could then copy these and fill them with content, and hopefully find a starting point that is somewhat near what they want to achieve.

I think the idea that people have to use the browser dev panel to make widgets is a “failure”. It means that you exclude most people from being potential widget creators. It might be hard to imagine how overwhelming all that is once you know most of it, but there are so many “implicit rules” in how HTML and CSS works, that you’re pretty much completely lost if you don’t know most of these. There’s no way to use reason or deduce how this works, you simply have to know - and if you don’t know, you’re lost.

I really don’t understand how that should work, F7 has gone down the route of “mobile-only” and has ditched support for desktop and remove things that “aren’t used by Google’s material design”. So, it will probably be increasingly difficult to get F7 to at all behave useful in a web browser in newer versions.

3 Likes

Jealous! No, ours was just the basic system.

Ok, I can see that I did make a couple of jumps there for users less familiar with the dev tools panel. Here’s the little background (for chromium browsers, at least, although I assume that others are fairly similar).

Yes, the element’s space is color coded. When you are using the elements tab in dev tools, you can select any html element in the page either by clicking on the element in the html viewer on the pane or using the inspect function (context menu or image button). When you hover over an element with the inspect function, or hover over the element’s html in the panel, the browser puts an overlay on the element itself to show the size, padding, and margins of that element:
image
The basic colors correspond to the detailed size and position display which is found in the computed css tab of the lower half of that elements panel.


(the last fill in the overlay, the purple with diagonal hash-lines is space the element is assigned that is unused by it’s child elements).

…maybe?..You can definitely change it, but the F7 Typography classes are only possibly going to be useful to you.

At it’s most basic, a class is just a tag for an html element. Like other tags, elements can have as many of them as you would like and they don’t do anything at all unless there is something else that takes advantage of that class. CSS selectors allow you to quickly identify all elements on a page that share some arbitrary combination of characteristics, including one or more classes. Both CSS and javascript can take advantage of this. Javascript, JQuery, and the like have functions that use CSS selectors to return arrays of elements for further processing, and CSS uses selectors to determine which elements to apply styles to. When you see:

stylesheet: >
  .big-red-button {
    color: red;
    font-size: 48px;
  }

in a widget, this is pure css and the .big-red-button is a CSS selector. The . indicates a class name and the class name is big-red-button. So, any element with the big-red-button class will now have those two styles added to it’s CSS hierarchy.

So, the difference between a class and a style is that a class can be a very useful shortcut to applying the same set of styles to lots of different elements instead of typing the same style info every time.

The F7 typography style classes share names with css styles because each of them applies only a single css directive to any element with that class. This is why I feel the F7 typography classes are only sort of useful. Any element with the display-flex class will have the display: flex style setting applied to it. From an ease of use standpoint when creating a widget, there’s virtually no difference between typing:

class:
  - display-flex

and

style:
  display: flex

I find the latter to be just plain more clear. Plus there is a good chance the component already has a style object so:

style:
  display: flex
  width: 100%

is just slightly more compact than:

class:
  - display-flex
style:
  width: 100%

The F7 classes are intended to be user-friendly for two reasons:

  1. They try to save the user from figuring out what value to give the style in cases where there are continuous options. For example, instead of trying to figure how big to make the top margin of a series of elements you can just use the margin-top class which will apply the css style margin-top: var(--f7-typography-margin)!important; and you will get a consistent (and responsive because of the f7 variable) style across all your elements.
  2. As you can see above, the F7 classes add the css keyword !important to the style as well. This keyword allows the style to override other attempts to set the same style from other sources. “I’ve set the width to 95px so why does my div still have a width of 100%?” is a very common CSS question because the final style value depends on the hierarchy of how each style was applied. !important is a kinda cheat to try and bypass this problem and can cause as many problems as it solves when overused.

In my opinion, neither of these benefits apply to OH widget creation. The first doesn’t apply because if a user wants to change that margin-top style it is often because the F7 default or it’s derivatives are not what is needed in that particular case. The second doesn’t apply because the component’s style object applies those styles at the element level which supersedes any class level styles (unless those class styles include the !important keyword).

I don’t think I have a single widget where I use one of the F7 typography classes. I just put everything in the style object instead. YMMV.

This is CSS. In addition to basic values with units, css has a series of functions that you can use as the value for a style. Not many of them will be useful for the average OH widget creator, but calc() is one of those that might ( var() like you see above in the morgin-top example is another). calc accepts any fairly standard mathematical statement but has the wonderful benefit of being unit aware so that you can combine any valid values for that style.

width: calc( (100vh - 48px) / 2 + 10%);

And, of course, functions can be combined:

margin-top: calc(var(--f7-typography-margin) / 2);

I don’t know when/if this true. I only know that the discussion that resulted in the move from Vue2 to Vue3 started with the idea of both a Vue update and an F7 update. It was, quite reasonably, decided that both was too much at once and since Vue3 is a requirement for F7 v8, the Vue update came first and is nearing completion. As @Nadahar points out, an update to F7 v8 would probably come with some significant design philosophy shifts (in my pseudo-educated opinion, some good and some less so), and, as in the case of the rows and cols, it would come with some major work to keep backwards compatibility or significant breaking changes. Maybe @florian-h05 wants to chime in about what his vision of the future for F7 in OH is?

Yeah, this is one of the biggest hurdles. I tried to at least address it a little when I added the Components section of the widget docs, but I agree there’s probably a better way to collate this for users.

The same accusations are leveled at OH docs on a regular basis. Writing goods docs is hard, tedious, and not very rewarding for many open source projects. What a world it would be if all software documentation were comprehensive and clear!

That’s exactly how I started. I had only dabbled in html and css prior to OH3. But, I discovered that I do find yaml extremely intuitive (I know many disagree with that opinion) and that intuitiveness stretched immediately to the widget system. I then learned a lot from looking at some of the early examples that Yannick put out and some of the great early work by @RGroll . Then I do what I always do in these situations. I a decide that based on my early success I concoct an overly complicated scheme to X. I believe deep down in my soul (usually completely without evidence or expertise in the matter) that X is possible, and then I work to learn whatever I need learn to make it happen and don’t take no for an answer. In this case, X was a series of three or four increasingly complicated widgets. It took some time, sure, but that was my project for those few months.

I think there’s something that gets lost a lot in these conversations and is evident in this one too (and not just in this particular comment). I tried to hint at it above, but maybe it should be more explicit. Yeah, users are often frustrated by the widget creation, because they are trying to do something “that should be simple” and struggling with it. When I say that the OH widget system is a pretty impressive success (and this, therefore also has to include to some extent the F7 material is it built on), I mean that what those users often don’t realize is just how amazingly far along the complexity axis ‘simple’ has been shifted by this system.

Rich started this thread with some questions about widgets that “should be simple” but I say heck no! There’s absolutely nothing simple about coordinating half a dozen different graphical inputs and displays in a concise location that has to interact smoothly with the other complexity around it, work well in different screen orientations and resolutions, and feel intuitive to users of all experience levels.

The OH widget system is not perfect, for sure, but it does so many parts of its job well enough that even fairly novice users start to push what they think they can “simply do”. In my opinion, that’s awesome.

My advice is that, when you are working on a widget and you get frustrated that something that “should be simple” isn’t working out as simply as you like, take a break and go try and put an image where you want it in a MS Word doc.

I would argue that, to a large extent, between the fact that users can see the yaml that results from widget configuration in the graphical wizards and the creation of the marketplace, OH has much of this already. Even if you say these aren’t unified enough or comprehensive enough, have you seen, for example, the great work that @DrScr3w is doing with his ScrewPlate library?

I see it differently. As I said above, it’s not only easy to imagine how overwhelming this is, it’s actually under-estimated by most users. As I also said above, however, I’m a teacher by trade. One of my most glaring character flaws is that I will always believe that anyone can learn anything under the correct circumstances. This is not a OH or browser or even tech issue. Complex things are overwhelming to those who first encounter them. You can look at that overwhelming object and decide not to tackle it (that’s ok, you’ve got other priorities), or you can decide that going from inexperienced to proficient in this arena is worth engaging with that overwhelming thing until it is no longer overwhelming.

The browser dev panel is overwhelming. I use the elements tab and console tab a lot. I use the sources tab occasionally. I went through overthewire and natas a while back so I’m familiar with some of the functions of the other tabs, but that was my choice because I wanted to learn those things. As soon as you have a personal reason to look past the overwhelming nature of something with complexity, it becomes a great way to learn about of a lot stuff.

1 Like

I’m not saying that doing this “right” is easy, or that there isn’t good information to be found already. I’m just saying that time and time again, if I try to do something, I end up spending a considerable amount of time trying to piece together different information from different sources. So, don’t see it as criticism, I’m merely stating that I think it is still a significant hurdle on the way to making something.

It is often true for OH as well, but I feel that F7 is consistenly without the interesting details, while with OH it isn’t true across the board. It’s also another significant difference in my opinion, OH generally (not always) has a logic that makes it possible to “guess” part of how things work. F7 almost completely lacks that in my experience, except for very basic things like that “a column constitutes a column”. But, the “rules” for how the components work usually isn’t documented at all, it’s just a “take it or leave it” attitude where you just have to accept the results of their opaque “rules” or struggle an impossible battle against an “invisible enemy”. Maybe the things they do are intuitive for others, but for me, they aren’t at all.

When it comes to writing documentation generally, it’s a challenge for many reasons. I see that myself, one of my biggest problem is to remember all the details from the time I write the code to the time where I’m supposed to document it. I’ve learned long ago that I can’t document things from the start, because I usually change or tweak things so many times that “maintaining” the documentation becomes a bigger task than the code, and it will often end up being inconsistent and not make a lot of sense. At the same time, I can’t wait until everything is done, because then I simply don’t remember.

What I try to do, is to do something in between. I make comments in the code // Doc: where I write how something works in a short form - which is much quicker to change underways. Then, when things have stabilized, I can use these “cues” as a reminder of what do document, and how things work. But, it’s not perfect by a long shot, and especially long wait times for PRs make writing documentation very hard. You never know what you’ll have to change, so you can’t write the documentation up-front, and by the time it’s finally merged, you have probably forgotten most of what you did.

All that said, I think OH does better with documentation than many other projects, even though it’s far from perfect. With F7 on the other hand, it feels like they didn’t even try. Their “documentation” is more a showcase of how they imagine people should use it, and anything that falls outside that scope is simply omitted.

I’m not saying that it’s impossible to figure out, just that it’s more work than most people are willing to commit. Also, personally, I just don’t do it often enough to remember what I’ve learned. I do lots of different stuff, so my mind have been many other places since the last time I did something similar, and the details are likely to be very fuzzy or completely absent. If I were to only do this, it would be different, but that’s not how it is, and I feel that there’s generally too many things you just need to remember to do something useful, for it to be suitable as a “tool” you can use every now and then, when needed, without being heavily invested.

I think that is only half-true. As I said above, when it comes to manipulating and presenting data, I largely agree. When it comes to layout, I disagree. If you just accept the layout you’re given, sure, it can be easy to live with, but if you don’t for some reason, you quickly end up fighting one thing after another.

As an example of this, I still primarily use sitemaps as my daily UI to interact with OH. That’s not because sitemaps are very good or powerful, but for the simple reason that they are fairly compact. I just don’t care about trends and fashion and what “looks modern”, I just want something to be functional. And, having to scroll like a mad person to see things just isn’t functional. I want as much information in front of me as possible, so that I can quickly orient myself and do what I want to do. MainUI/F7 is just useless at this. You will have to fight for every piece of useless whitespace that you want to get rid of, and if can count on that if you ever get something to be reasonably compact, it will break because of some update, or if you view it form a different system. For me, this is the one point that has stopped every attempt I have made at migrating from sitemaps.

It’s evident that those that “designed” F7 frowns at the idea of a compact layout. They don’t understand what it means to be functional or practical, they only care about following whatever they deem as “the latest trend” in how things should look. If you agree with that idea, I’m sure you’ll be mostly fine, but if you don’t, you’re simply out of luck. It’s not flexible at all in that sense, and all the “simplifications” end up working against you because they constantly “impose something that you don’t want”.

So, I see it as something of a “one-hit-wonder”, it can only really do one thing. A good and flexible framework is unbiased in my view, it doesn’t impose decisions on you, it gives you the tools to create what you want. F7 is the opposite of that. It’s a bit like Apple: “We have simplified everything by making all the decisions for you. If you disagree with our decisions, submit or die”.

I say “heck yeah”. It is simple in that it’s not a very complicated design, and you could write down a relatively brief set of rules for how it should work that would explain everything “Align X with Y, scale Y according to Z, etc.”. It’s not complex. What is complex is getting HTML/CSS to do it, and this has a long and complicated history where many short-sighted decisions have been made along the way that have later ended up being hurdles that you can’t really get rid of. The “ad hoc” nature of it all is very evident, and the end result suffers heavily from none of it really having been properly designed, it’s just been tweaked and tweaked and tweaked, endlessly. JavaScript suffers from the same thing, for the same reasons, as it has also been “shaped” by this frankly quite screwed up process. So, if you look at it from a HTML/CSS perspective, sure, it’s complex. But if you don’t know HTML/CSS and look at with a human perspective, it is simple. Who is “right”, HTML/CSS or the human? All I know is that while HTML/CSS can solve some things very elegantly, it can make other things almost impossible to achieve. It shouldn’t be that hard! But, this is a failure of HTML/CSS and domination by big business that only care about their needs, and isn’t something that OH can do anything about. I just like to point out that I don’t think people are wrong when they many times think something should be simple, and the reality is very different with HTML/CSS. Instead of trying to explain to people why “they are wrong”, we should explain that sadly, doing things like this hasn’t been a priority for those that have made the decisions, and as a result, this is either very difficult or impossible to achieve.

MS Word isn’t exactly “strong” when it comes to layout. It’s the exact opposite, in fact. It’s completely unsuitable for layout, it produce an unpredictable mess of all but the simplest constructs. But, to write a letter where all you need is a couple of fonts and some paragraphs, it does the job. Anybody that wants to do layout, does so in a tool that is actually capable of layout, like Adobe InDesign. So yeah, if you want to argue that MS Word is probably even more limited layout-wise than HTML/CSS, you’ll be right - but I’m not sure how much that assertion is worth. It certainly doesn’t mean that HTML/CSS is good at it.

Yes, there are many great things spread all around, the problem is to get an overview when you need it.

It’s funny to read that, I constantly gets reminded that I do the exact same thing. I assume that very few things are so difficult or complex that people can’t do it if they want to. I’m often told that I’m wrong, maybe I am, or maybe I and others have a different definition of “want”. Is that just a desire, or is it backed up with a willingness to invest some effort?

That’s not really my point here. I’m not arguing that this is an insurmountable challenge, I’m rather arguing that it is presented as “the widget system is so powerful and flexible that you can easily make widgets customized to your needs”, while the truth is that, it neglects to include “if you’re willing to invest the tiem and effort to become proficient in HTML/CSS”. If people expect that they should be able to do this without knowing HTML/CSS, they will quickly hit more trouble than they can cope with, and that in a way, is the problem.

I don’t think the dev panel itself is that overwhelming, if you know what the things it shows are/how they work. But, if you don’t, it’s certain to be close to useless. I usually do just fine there. I regularly use “Elements”, “Console”, “Sources”, “Network” and “Vue” tabs. They are all fine if you know anything about the content they show. But, if you only want to figure out how to get an element in a widget to align properly, and have no knowledge of the data that is presented in these tabs, they are “useless”.

Rich,Justin, and Nadar, thanks for this post. It echoes frustrations I’ve felt every time I’ve tried to do creative widgets. I first got into web dev in another century when CSS was just a proposal, and a few years ago when I retired, I could do anything I wanted with it. F7 is a bit like OH in that you have to climb a bit of a hill to understand intuitively what will happen when you do “x”, and then things start to get easier. I haven’t invested the time to crawl far enough up that hill, but @JustinG has provided me with some incentive to take a swing at it. I suspect that I’m like many OH users in that my system hums along happily until I decide to do something new, at which time I’m rebuilding my knowledge base from the last time. I have a few widgets that are almost good enough in my system; I need to take a fresh look at them and put some more time into understanding F7’s philosophies.

One thing that always slows me down is that F7 docs show examples in HTML and I have to translate back in my head into what yaml might get the result I want, and then sort out what OH may have layerd onto it behind the scenes. I’m also a heavy user of the webdev tools, and will experiment by modifying styles on the fly to get an idea of whether changes will get where I want to go.

This is not a thread about the historical adequacies/inadequacies of the tools we have. For better or worse, html, css, and javascript are the tools available to us. This is about how best to use OH widgets to interact with those tools; so, I really only want to point out one thing:

This is not accurate at all. I just spent many hours and too many words above explaining why this is not necessarily easy. It’s not even the “official” opinion…

From the docs:

The complete flow looks like this:

YAML → Vue (Framework7) → HTML

For basic widgets this information is only sometimes relevant, but when creating more advanced, complex widgets it is often critical to understand this for successful structuring and debugging.

Oh, and then there’s an entire page of the docs just on the complexities of css in your widget…

OH is fairly easy and user friendly because now with MainUI a novice can come in and use the graphical wizards, and the pre-built components, and get a result that is usable, visually appealing to many people, and functional. OH is appealing to more advanced users because when you feel like moving on beyond that “simple” setup there are systems that provide you all the complexity you need.

A quick search on the forums and you will find 100 posts where I have advised a user that when they go beyond placing the standard components in standard arrangements what they are trying to do is achievable but probably not easy.

This is a false equivalence and exactly the mindset that I am pushing back against. Even someone like you with a lot of technical experience and skill falls into this trap. If this were easy, front-end dev wouldn’t be an entire career. The “I can say it in a few words so it must be easy for you to do” fallacy is exactly why engineers find managers exasperating.

I can sketch a car. I could probably even build something with four wheels, a battery, an old electric lawn-mower motor, a seat, and a steering post just from junk in my garage. That will not be a car that anyone would want to use or would even be capable of 1% of the things that the average person needs/wants from their car. I can write down in a few sentences my idea for a brilliant new app. So, coding it should, by your argument, be easy.

It’s also not a matter of the quality of the tools. I can give you an hour long lecture on the physics of powered flight from birds to ramjets. If you put me on the Boeing factory floor, I’d probably put the wrong bolts in the emergency door too.

One of the most common question forms that I answer about widgets is, “I’ve made this widget that looks right in Scenario A, but in Scenario B it’s all wrong…why?” Well, the ‘why’ is because it is to easy craft something static that looks right, but there is absolutely nothing static about modern UIs and Scenario A is only one small fraction of where that widget you just built is going to wind up.

You even stated the true issue yourself:

Yes! Your “simple” sketch of a widget doesn’t even begin to address the thousands of decisions that have to be made for that widget to be useful in a real-world setting. Your arguments about the F7 library don’t apply here for this exact reason; if you want to go beyond the simple where those decisions have been made for you by the F7 devs, OH widgets give you all the arbitrary html tags you want to make those decisions yourself. Sure, a layout page will start with an F7-based frame because that is how OH is built, but inside that page you can create as compact a dashboard as you like with nary a single F7 component taking up extra space. Or, go even further. With the OH API, you can create your own webpage completely devoid of all the “horrible, poorly-designed, wasteful” F7 non-sense and still have access to all your OH information. But, those are not easy and they are time consuming, and so, it makes more sense for you in your situation to stick with sitemaps. That’s a fine choice, but that is not a reflection on the capabilities system.

My argument is only this: From my personal experience on these forums, the OH widget system encourages this “it should be simple” attitude because it really does make early successes fairly easy to come by even for very inexperienced users. And, in my personal opinion, that’s a good thing because then they have some confidence and reason to try to go further. However, when they do go further they bump into a complexity wall and that’s why we need forums that help them and threads like this.

I agree that this really is the core of being able to take the step from working within the boundaries of the pre-made components to striking out on your own with complex custom components (it’s the very first thing I said in my initial reply). Unfortunately, I’m not sure how to help speed users along this path. This really is a language learning step, and you can be told all the rules, tricks, and quirks, in a language a hundred times over but you never really internalize a language until you use it.

1 Like

My whole reason for pointing to that is to try to get the message across that what make many things complex it the shortcoming of those tools, not the task itself. Which is why this “cognitive divide” exists between those who know HTML/CSS and those who don’t. It gets complicated the moment you try to translate relatively simple rules into something HTML/CSS can handle, it isn’t complicated before that - but when your mind is very “integrated” into the world of HTML/CSS, this “translation” starts immediately, which is why you deem something complex/complicated from the start.

I guess this is where we disagree fundamentally. I see what is supplied if you just accept the layout as it is as “non functional” in practice, because it requires so much scrolling that I at least just feel frustrated. The fact that some of the controls are often “activated” when you scroll (sliders for example) makes this even more frustrating.

Yes, and if you view things like I do, where this is basically required to make it usable, then “it’s not easy” period.

There’s no false equivalence - I’m just trying, and obviously failing to, convey a point. The fact that “front-end dev” has become a career of its own, is quite mind-boggling to me, and I see that largely as a result of the failure of HTML/CSS and the whole short-sightedness that has dominated browser development. But, that’s off topic here. My point isn’t that it’s easy to do, it’s that the concept is simple, and that’s the reason that people that don’t know the limitations of HTML/CSS think it should be simple.

When you end up in the situation over and over again where you have to explain to people that “the seemingly simple task you’re trying to achieve is in reality very difficult”, shouldn’t that be a hint that maybe all those people aren’t “wrong”, but the limitations of the tools are?

Absolutely not, what I’m saying is that the fact that coding it might be complex doesn’t make the idea complex. Sometimes it’s complex simply because people haven’t though through what their “idea” entails, the complexity comes from all the details that must be handled. But, other times, the complexity comes from limitations in the tools, and the fact that there’s no way to do something that could have been possible, if someone hadn’t made a decision that made it impossible.

I really don’t follow here, the quality of the tools often make a huge difference (I also am quite familiar with mechanics and can repair pretty much anything on a car). But, knowledge of aerodynamics is useless if you want to build a plane. It’s not useless in the design phase, but when it comes to actually building it, you need completely different skills. You need to know materials, how they behave under different circumstances, the strength of different shapes and material combinations, how to shape materials into the shape you want, and of course a lot about “current standards and requirements” so that you can navigate the things you have to work with.

Once you have a shape that will fly, aerodynamically, a plane isn’t “complex”. It’s very simple, you need some form of propulsion that will give you enough speed to create the lift you need to make your shape fly, and you need some control surfaces that let you decide where it should go. There are plenty of older plane designs that are very simple, and that fly perfectly fine. I particularly love some of the biplane designs in wood, canvas and wires. They are beautiful in their simplicity. Also, if you throw enough propulsion at it, you can make almost anything fly.

What makes a “modern aircraft” complicated is the requirements we make for how we want it to operate. We want a certain speed, a certain noise level, energy efficiency, carrying capacity, redundancy, comfort etc., etc. This is where the complexity comes from, the basic concept of a “traditional” fixed-wing aircraft with two wings for lift and a tail for controlling direction is still simple in my view.

Yes, it’s obviously much easier to just nail everything in place where you want it, than to make rules for how the elements should relate to each other, and make them work under different circumstances. But, I still maintain that the shortcomings of HTML/CSS makes this a lot harder than it should be.

I don’t follow here. I’m not arguing that things are impossible if you accept any level of effort to achieve them, although I’m pretty sure that some things still are, I’m arguing that doing this isn’t practical. The cost/benefit calculation doesn’t make sense. If I have to design everything “from scratch”, using HTML/CSS and ditching all F7 and OH components, these things, and YAML, would just be a hindrance. It would make more sense to write a UI from scratch then, where you didn’t have to constantly fight a lot of undocumented, invisible things that try to sabotage everything you do. But, I have no interest in putting anything close to that amount of effort into getting a functional UI for OH. So, even if it’s “technically possible”, it is, as far as I’m concerned, beyond what is “practically feasible”.

I disagree. The “my way or the highway” nature of this, is the limitation in capability. If it were flexible, you could achieve more than “following one narrow path” without going outside what the system can do. I feel that your argument is similar to: “This car isn’t suitable for me, because there’s no room for my dog. Wrong: Just get a welder and cut and weld the car into the shape you need to have room for your dog. This isn’t a limitation of the car”.

Everyone is right to some degree here. You can in fact make usable pages with a fairly low effort, but as soon as you run into something you can’t represent, or can’t determine how to represent (which is different, but yields the same outcome), you cross that line from simple to not.

It’s also extra painful right now, because the UI widget marketplace is broken, so you can’t easily look for something that looks like what you want to crib from it.

  • How do I know when to use a grid vs flex? The docs assume you know and give you syntax.
  • Look at oh-grid-layout vs f7-grid. There is an example, with a visual representation of the output. What benefits does oh-grid-layout have over f7-grid? I’m left to guess.

Every time I get into one of these projects, I think “I should submit a PR for a doc update”, then get caught in a loop of not being sure I have enough info to improve it and get my thing sortof working and move on with my non OH projects.

I’m going to take my recent widget and try to convert to oh-grid-layout, and see if I can propose a PR with some user-focused info to add to the reference info. We’ll see how that goes. I’m going to take the position that I’ll write down what I know, and if it’s wrong or incomplete, someone will help me correct it before merging.

1 Like

I’ve never meant to say that this isn’t the case, I’m just saying that I feel that the “path” on which you must stay to avoid all the difficult stuff is very narrow - too narrow in my opinion, and I blame that mostly on F7.

1 Like

We’re on the same page.

1 Like

And let me just add that I really enjoyed this discussion and learned quite a bit again. I can totally see both sides. It also showed me that I’m definitely not the only one who regularly feels too dumb to make a widget :sweat_smile:.

While I haven’t had many great experiences with AI when it comes to coding, it has sometimes helped me figure out where to fix a gap or align something properly when building widgets. Maybe that’s the kind of direction — with the right MCP — that could help bridge the gap between the pains of CSS and the average enthusiastic user a bit in the future.

1 Like

I think I understand all of that except for how to apply this knowledge to widget development. We are not creating classes and only using what’s already been defined. But it sounds like you suggest we shouldn’t try to use the F7 classes anyway which means we should generally just use the style section of config and CSS display-flex’s docs as our reference, correct?

Just to make sure I’m understanding, that line changes the top margin to be half of what F7 set the margin to for this specific widget, right?

These docs are good and I learned a lot from them, but I think they assume too much knowledge on the reader’s part. For example:

The most commonly used F7 components will likely be f7-block , f7-row , and f7-col . These all generate a simple <div> element with one base F7 class (block , row , and col respectively).

What’s a <div>? What’s it mean to me the end user? I kind of understood what that sentence meant, but it really wasn’t until this thread that I really understood.

And what I lack on that page is how it all fits together. Something like a step-by-step tutorial is needed I think. Getting started doesn’t go deep enough (as it’s currently written) though. It just presents the happy path where everything looks like you want it to and doesn’t even go into adjusting it,how to lay out the grid/flex flow, or anything like that.

And maybe it doesn’t belong there. But I feel we need it somewhere. I can’t speak for everyone, but I could surely use some hand holding to leap from “just use the oh-X widgets” to “let’s create a widget for a whole equipment with reasonable alignment and resizing behavior”.

Note to self, the Getting Started pages tutorials need to be updated.

One thing that prompted my post was that there is a Grand Canyon sized gap between the two. It felt like I was missing something. I asked myself “do I really need to become proficient in basic HTML/CSS/F7 development just to control how this stuff aligns?”

It seems the answer is “yes” which begs the question, what can we do in code, UI design, and/or the docs to shrink that gap a little. Or build a bridge over the canyon, e.g. a “Just Enough CSS to Build a Moderately Complex Widget” tutorial which does not require going outside of OH to learn. And by moderately complex I mean a widget like I posted above with a few rows, a few columns, and the ability to control:

  • how it resizes
  • justification
  • anchors (pinning a widget to the left, right, top, bottom, or center)
  • how to identify what is causing what (i.e. how to use the browser developer tools)
  • where to go when even this tutorial isn’t sufficient, i.e. next steps on your learning journey.

Nothing more than that I think is really needed and that should shrink that gap significantly. I know it’s impossible to eliminate the gap entirely, but it feels too wide right now. And this will be laser focused on one approach (i.e. we either show the f7 way or the pure DIV/HTML/CSS way). We are not trying to be comprehensive here. We are just trying to build a little larger foundation of knowledge upon which users can build.

Don’t get me wrong, the docs have improved tons since OH 3 first came out. oh-context, the shorthand ways to do common stuff, and the documentation on expressions and such is so so much better. But I personally feel like I lack a way to tie them all together and use them to solve my problems. I’m hoping to take what I’ve learned from this thread so far and maybe build the outline for something, but I need to actually put it all into practice and make sure I’m understanding it.

My intent with this thread is not to go through the history of HTTP/CSS/F7 and all the “wrong” decisions they’ve made over the decades. We live in this current world with these current technologies. What can we actually do in this world with these technologies to make widget development easier for our users? “People made bad decisions” doesn’t help me with that.

It’s looking like the images on those posts are simply gone. I intend to make an effort to regenerate the screenshots for the widgets I’ve posted. If I can get some volunteers we could make a concerted effort to, as a community, regenerate all the screen shots. As a moderator I have the ability to edit the original posts on the marketplace. Perhaps we can at least fix the marketplace.

That’s what I do, but only because I feel it is a more clear and consistent approach. There is nothing you can do with the f7 classes that you cannot do just as easily with the the style section and there is much that you cannot do with those classes. So, to me, it just makes the most sense to ignore them and always set the css directly in the style.

100% correct.

A while back (was it the OH4 wishlist thread?), someone specifically listed “more widget examples by JustinG” as a wishlist item. I’ve been thinking about this on and off ever since, but I haven’t really gotten anywhere because, to be honest, I have no idea where to start. I can easily (usually) answer specific questions such as these here all day long, but I also wrote that section of the docs that you just cited as jumping ahead too far.

I’m not sure I’m the person to write a basic html and css guide, plus those are already a dime a dozen on the net.

So, getting some census on what a couple of good early examples might be would be a great place for me to start. Then I could do some more work ups similar to what here and try and pitch them a little better based on what people really feel that they need.

I don’t know if that’s a whole new thread (Post your basic widget idea’s here and I’ll do a basic structure work up). This thread is helping me get a better idea of where the gaps are for sure, but I’m not sure what those real world examples that will resonate will users most actually are.

1 Like

A class in CSS has very little resemblance to what it means in most other contexts. You don’t “create” them, you just use them. Think of them more like some kind of tag. So, you can just pick a class, apply that, and then in your stylesheet, you can apply specific styles to every element that is tagged with that class.

A <div> is one of the, if not the most, basic HTML building blocks. It’s basically just a basic element with no properties before you assign them, but by being “an element” in inheritably possesses that ability to have its own properties.

When it comes to what it means to the end user… that’s what I’ve been trying to get at. Most of this is completely unavailable to anybody that doesn’t know HTML/CSS.

The answer is yes, which is what I’ve been trying to point the finger at. You can’t really even do basic layout things without going to the HTML/CSS level.

I think that is very hard to do because HTML/CSS is such a mess. It has all these implicit rules that, if you’re not aware of them, it’s basically unmanageable.

That’s what I’m criticizing F7 for, it doesn’t allow any deviation in style unless you go full HTML/CSS and basically override what F7 does. To me, a “framework”, allows tweaking basic stuff without jumping in at the deep end.

My intent with saying this wasn’t to go through the history of this, but to try to get the point through that the complexity comes from HTML/CSS and its shortcomings, not what you want to do. “People made bad decisions” is relevant in the sense that I don’t think it’s reasonable to just say that “well, people just gotta learn this if they want to do anything”.

If that’s the case, it’s a huge disaster - and it should be stated clearly. Is there no backup? I have used plenty of screenshots that I haven’t stored anywhere else, just pasted directly into the forum. If these are gone, there’s no practical way to get many of them back.

I don’t think we need more examples. I think what we need is a narrative. A story that walks us through the development of a widget. Believe-it-or-not, you’ve kind of already posted a good chunk of such a narrative above in your first reply.

Something like:

  1. I want to make a widget to consolidate all the information about my humidifier
    a. list some requirements, maybe include a hand drawn sketch
  2. Build the initial widget applying the “bare minimum” principal
    a. be sure to talk about properties
    b. be sure to talk about oh-context
  3. Ugh, it doesn’t look right, identify all the things we want to change and walk through the steps to fix them for each identified thing to fix
    a. figure out what part of the widget needs to be adjusted, here is where you bring up the web developer tools in the browser
    b. figure out what to change based on 3.a. (links to reference docs and a little discussion about how to use them)

It’s the process that needs to be presented, not all the reference details. It’s the context that is missing. We are working in OH but pointing to the F7 docs and CSS reference docs et. al. loses that context. I follow the link and immediately get lost because nothing told me how to apply the information I find there to YAML in the OH context.

I’m really not looking for that. I’m, more looking for process and the secret decoder ring for how to use the external reference docs and apply them to OH.

The widget I posted would be a good candidate I think. It’s just interesting enough to need a little extra work to make it right but not so complicated that we need to get too deep in the weeds.

A widget that includes a bunch of buttons would be useful I think.

A player widget similar to what I used in the Getting Started Tutorial (only perhaps better constructed and laid out) could be another one. These are what I’m thinking off the top of my head.

I’m not looking at stuff like animation, SVG widgets that look like remote controllers or the actual thermostats or anything super complicated or custom. Just taking combining a bunch of the existing oh-X widgets on some rows and columns.

The question was rhetorical. It’s the question a lot of our users will ask themselves upon reading that sentence. I personally know what a div is.

So we should just give up? Sorry, widgets are hard, and we are not even going to try to help make it easier? No, I vehemently disagree and will not stop trying to make it better.

See OH Community Site Images Missing?. It’s been months and no progress has been made so :person_shrugging: I’ve no idea if they are gone forever or not. But the longer we go without a resolution the worse the situation becomes.

No, I just think that this deserves “to be taken seriously”, not just brushed off with “learn HTML/CSS”. I think some kind of theme functionality would be a good start, where you could apply this “theme” globally or to a subset/group of components. It should contain basic stuff like margins, fonts, colors etc. I think that along could go a long way in making it all manageable, as long as this overrides what F7 enforces.

When it comes to element alignment relatively to each other, it would probably be much harder to make something that would allow users to avoid HTML/CSS. But, maybe some “standardized way” of doing it could be suggested (e.g. use Flexbox, apply the following properties in this way to achieve that effect). I’m no expert at this, so I don’t know what would be the best solution, but I think it would be a vast improvement if there were some “help” to handle these things instead of just telling people to “figure out” using F7/HTML/CSS.

I’m not brushing it off, I’m looking for a way to deal with it.

Great idea! Now we need someone to go built it. In the meantime, what can we do with what we have?

Is this not exactly what I’m recommending?

It’s pretty feature complete, providing many components for many use cases. TBH I don’t think there is a single UI library out there where you can design exactly what you want without going into the depths of the how, which is HTML/CSS in case of browser environments.
So yes, you have to know HTML & CSS to customise F7, but it does a pretty good job of providing reasonable defaults.

The Aurora theme is only a big bunch of CSS variables … I have been able to get the Framework7 v5 style on Framework7 v7 by simply swapping out the Framework7 CSS file.
So I think it might be possible to do this trick to get Framework7 v8 running with the Aurora theme.

Framework7 is going to stay, there are no plans of moving away from it. We have recently upgraded from Vue 2 → 3 and Framework7 5 → 7. Being on Vue 3 is quite important, as Vue 2 is EOL and so the Vue ecosystem is only evolving for Vue 3. As we are now on Vue 3, we can do anything we want, the Framework7 version doesn’t really matter – Framework7 is providing components and routing, but it is not the technological base.
We might switch from Framework7 router to Vue router though, currentlly experiencing many issues with Framework7 router.

1 Like