Responsiveness in custom widgets

Hello,

I have a custom widget that I am trying to make it resize as I use OpenHAB from different devices such as: PC, Mobile. I have created this widget as shown below, I am trying to make the buttons collapse down as the resolution changes, but I am not able to achieve this as desired. I am using flexbox already, but I still have some issues when I use the widget on a page:

(1)

(2)
I want to be able to achieve something like this when I resize the resolution down:

the problem is I want the initial widget dimensions to be the same as in picture (1) with a max width of 600 px for example, and then as I resize it down, it should collapse to the point it reaches as in picture (2), and to be responsive for mobile devices at the same time.

currently I am using f7-block for the root component of the widget, I tried f7-col and changing some widths but I couldn’t achieve the desired purpose as I explained previously.

I don’t want something like this to happen:


you can see that the widget is overlapped in the browser where it should like resize instead.

Edit: I tried changing the width of the root component and used relative units such as vh
and got to this point as shown:

Still is there a way to specifically let the widget fill the empty white space on the right? At the same time I don’t want it to fill the entire width space when I use openhab from PC. This is the full YAML code of the widget:

uid: AC_Mode_Master
tags: []
props:
  parameters:
    - description: Label for room
      label: Room Label
      name: roomLabel
      required: false
      type: TEXT
    - context: item
      description: item for AC status
      label: AC ON/OFF
      name: acStatusItem
      required: true
      type: TEXT
    - context: item
      description: item for AC Optimization Mode
      label: AC Optimization Mode
      name: acOptModeItem
      required: true
      type: TEXT
    - context: item
      description: item for AC Setpoint
      label: AC Setpoint
      name: acSetPointItem
      required: true
      type: TEXT
    - context: item
      description: item for Room Temperature
      label: Room Temperature
      name: roomTempItem
      required: true
      type: TEXT
    - context: item
      description: item for AC Heat Mode
      label: AC Heat/Cool
      name: acHeatModeItem
      required: true
      type: TEXT
    - context: item
      description: item for AC Fan Speed
      label: AC Fan Speed
      name: acFanSpeedItem
      required: true
      type: TEXT
    - context: item
      description: item for AC Fan Speed Selection
      label: AC Fan Selection
      name: acFanSpeedSelectionItem
      required: true
      type: TEXT
  parameterGroups: []
timestamp: Aug 5, 2024, 10:21:10 AM
component: f7-block
config:
  style:
    background-color: rgba(228,237,246)
    border-radius: 20px
    width: 35vw
    min-width: 250px
slots:
  default:
    - component: f7-row
      config:
        class:
          - display-flex
          - justify-content-center
      slots:
        default:
          - component: f7-row
            config:
              class:
                - padding-half
                - justify-content-center
            slots:
              default:
                - component: Label
                  config:
                    style:
                      text-align: center
                      color: RGB(79, 92, 106)
                      font-size: 20px
                      width: 100%
                    text: '=props.roomLabel ? props.roomLabel : "Room Name"'
                - component: oh-icon
                  config:
                    icon: iconify:iconoir:air-conditioner
                    style:
                      color: '=items[props.acStatusItem].state == "ON" ? "lime" : "red"'
                      height: 40px
                      width: 40px
                - component: f7-chip
                  config:
                    style:
                      background-color: rgba(0,0,0,0.1)
                      color: RGB(79, 92, 180)
                      justify-content: flex-end
                    text: '="Room: " + (items[props.roomTempItem].state ? Number.parseFloat(items[props.roomTempItem].state).toFixed(1) + " °C" : "-")'
          - component: f7-col
            config:
              style:
                display: flex
                height: 100%
                width: 100%
                flex-direction: column
            slots:
              default:
                - component: f7-row
                  config:
                    style:
                      display: flex
                      flex: 1
                      align-items: center
                  slots:
                    default:
                      - component: Label
                        config:
                          style:
                            text-align: left
                            color: RGB(79, 92, 106)
                            font-size: 15px
                            margin: 8px
                            flex-grow: 1
                            flex-shrink: 1
                            flex-basis: auto
                          text: Opt Mode
                      - component: oh-button
                        config:
                          action: command
                          actionCommand: 1
                          actionItem: =props.acOptModeItem
                          iconSize: 32
                          style:
                            align-items: center
                            background: '=items[props.acOptModeItem].state == "1" ? "rgba(63, 74, 144, 0.8)" : "rgba(0,0,0,0.1)"'
                            borderRadius: 10%
                            color: '=items[props.acOptModeItem].state == "1" ? "white" : "RGB(79, 92, 180)"'
                            display: flex
                            font-weight: bold
                            height: 50px
                            justify-content: center
                            margin: 8px
                            width: 90px
                            flex-grow: 0
                            flex-shrink: 0
                            flex-basis: auto
                          text: Comfort
                      - component: oh-button
                        config:
                          action: command
                          actionCommand: 2
                          actionItem: =props.acOptModeItem
                          iconSize: 32
                          style:
                            align-items: center
                            background: '=items[props.acOptModeItem].state == "2" ? "rgba(55, 65, 126, 0.8)" : "rgba(0,0,0,0.1)"'
                            borderRadius: 10%
                            color: '=items[props.acOptModeItem].state == "2" ? "white" : "RGB(79, 92, 180)"'
                            display: flex
                            font-weight: bold
                            height: 50px
                            justify-content: center
                            margin: 8px
                            width: 90px
                            flex-grow: 0
                            flex-shrink: 0
                            flex-basis: auto
                          text: Precomfort
                      - component: oh-button
                        config:
                          action: command
                          actionCommand: 3
                          actionItem: =props.acOptModeItem
                          iconSize: 32
                          style:
                            align-items: center
                            background: '=items[props.acOptModeItem].state == "3" ? "rgba(47, 56, 108, 0.8)" : "rgba(0,0,0,0.1)"'
                            borderRadius: 10%
                            color: '=items[props.acOptModeItem].state == "3" ? "white" : "RGB(79, 92, 180)"'
                            display: flex
                            font-weight: bold
                            height: 50px
                            justify-content: center
                            margin: 8px
                            width: 90px
                            flex-grow: 0
                            flex-shrink: 0
                            flex-basis: auto
                          text: Protection
          - component: f7-col
            config:
              style:
                display: flex
                height: 100%
                width: 100%
                flex-direction: column
            slots:
              default:
                - component: f7-row
                  config:
                    style:
                      display: flex
                      flex: 1
                      align-items: center
                  slots:
                    default:
                      - component: Label
                        config:
                          style:
                            text-align: left
                            color: RGB(79, 92, 106)
                            font-size: 15px
                            margin: 8px
                            flex-grow: 1
                            flex-shrink: 1
                            flex-basis: auto
                          text: Setpoint
                      - component: Label
                        config:
                          style:
                            text-align: left
                            font-weight: bold
                            color: RGB(79, 92, 106)
                            font-size: 14px
                            margin: 8px
                            flex-grow: 0
                            flex-shrink: 0
                            flex-basis: auto
                          text: '=(items[props.acSetPointItem].state ? items[props.acSetPointItem].state + " °C" : "-")'
                      - component: oh-button
                        config:
                          action: command
                          actionCommand: =Number(items[props.acSetPointItem].state.split(' ')[0]) + 1.0
                          actionItem: =props.acSetPointItem
                          iconF7: arrow_up_circle
                          iconSize: 40
                          style:
                            color: RGB(255, 140, 0)
                            height: auto
                            display: '=items[props.acOptModeItem].state == "3" ? "none" : "block"'
                      - component: oh-button
                        config:
                          action: command
                          actionCommand: =Number(items[props.acSetPointItem].state.split(' ')[0]) - 1.0
                          actionItem: =props.acSetPointItem
                          iconF7: arrow_down_circle
                          iconSize: 40
                          style:
                            color: RGB(255, 140, 0)
                            height: auto
                            display: '=items[props.acOptModeItem].state == "3" ? "none" : "block"'
          - component: f7-col
            config:
              style:
                display: flex
                height: 100%
                width: 100%
                flex-direction: column
            slots:
              default:
                - component: f7-row
                  config:
                    style:
                      display: flex
                      flex: 1
                      align-items: center
                  slots:
                    default:
                      - component: Label
                        config:
                          style:
                            text-align: left
                            color: RGB(79, 92, 106)
                            font-size: 15px
                            margin: 8px
                            flex-grow: 1
                            flex-shrink: 1
                            flex-basis: auto
                          text: Fan Speed
                      - component: oh-icon
                        config:
                          icon: iconify:iconoir:wind
                          style:
                            color: '=items[props.acFanSpeedItem].state == "100" ? "#FF8C00" : (items[props.acFanSpeedItem].state == "67" ? "yellow" : "#98FF98")'
                            height: 40px
                            width: 40px
                      - component: oh-button
                        config:
                          action: command
                          actionCommand: "0"
                          actionItem: =props.acFanSpeedSelectionItem
                          iconSize: 32
                          style:
                            align-items: center
                            background: '=items[props.acFanSpeedSelectionItem].state == "0" ? "rgba(128, 0, 128, 0.8)" : "rgba(0,0,0,0.1)"'
                            borderRadius: 10%
                            color: '=items[props.acFanSpeedSelectionItem].state == "0" ? "white" : "RGB(79, 92, 180)"'
                            display: flex
                            font-weight: bold
                            height: 50px
                            justify-content: center
                            margin: 8px
                            width: 90px
                            flex-grow: 0
                            flex-shrink: 0
                            flex-basis: auto
                          text: Auto
                      - component: oh-button
                        config:
                          action: command
                          actionCommand: 1
                          actionItem: =props.acFanSpeedSelectionItem
                          iconSize: 32
                          style:
                            align-items: center
                            background: '=items[props.acFanSpeedItem].state == "33" ? "rgba(219, 112, 147, 0.8)" : "rgba(0,0,0,0.1)"'
                            borderRadius: 10%
                            color: '=items[props.acFanSpeedItem].state == "33" ? "white" : "RGB(79, 92, 180)"'
                            display: flex
                            font-weight: bold
                            height: 50px
                            justify-content: center
                            margin: 8px
                            width: 90px
                            flex-grow: 0
                            flex-shrink: 0
                            flex-basis: auto
                          text: Low
                      - component: oh-button
                        config:
                          action: command
                          actionCommand: 2
                          actionItem: =props.acFanSpeedSelectionItem
                          iconSize: 32
                          style:
                            align-items: center
                            background: '=items[props.acFanSpeedItem].state == "67" ? "rgba(219, 112, 147, 0.8)" : "rgba(0,0,0,0.1)"'
                            borderRadius: 10%
                            color: '=items[props.acFanSpeedItem].state == "67" ? "white" : "RGB(79, 92, 180)"'
                            display: flex
                            font-weight: bold
                            height: 50px
                            justify-content: center
                            margin: 8px
                            width: 90px
                            flex-grow: 0
                            flex-shrink: 0
                            flex-basis: auto
                          text: Med
                      - component: oh-button
                        config:
                          action: command
                          actionCommand: 3
                          actionItem: =props.acFanSpeedSelectionItem
                          iconSize: 32
                          style:
                            align-items: center
                            background: '=items[props.acFanSpeedItem].state == "100" ? "rgba(219, 112, 147, 0.8)" : "rgba(0,0,0,0.1)"'
                            borderRadius: 10%
                            color: '=items[props.acFanSpeedItem].state == "100" ? "white" : "RGB(79, 92, 180)"'
                            display: flex
                            font-weight: bold
                            height: 50px
                            justify-content: center
                            margin: 8px
                            width: 90px
                            flex-grow: 0
                            flex-shrink: 0
                            flex-basis: auto
                          text: High

A short snippet doesn’t really do us any good at all, and a screenshot makes it impossible for us to actually evaluate the code. If you want specific help, please post the entire widget code in code fences:

```
widget code here
```

It’s possible that you can get the effect you are looking for with one set of styles or just use of the oh-grid column size settings on the page (hard to say with the information provided). However, if you truly want differing style behavior at different screen resolutions then you will need to use the stylesheet property to add a full css declaration at the start of your widget and use a media query block:

1 Like

I edited the post and included the full YAML, I will try and take a look at media queries.

can you provide a simple example?

I tried something like this but the effect wasn’t applied:

component: f7-block
config:
  style:
    background-color: rgba(228,237,246)
    border-radius: 20px
    width: 35vw
    min-width: 250px
    stylesheet: >
      @media screen and (max-width: 768px) {
        .responsive-width {
          width: 100vw
        }
      }
  class:
    - responsive-width

There are a few issues with this:

Your stylesheet is indented to the same level as the keys within the style object. The stylesheet is separate; it should be its own key within the config object.

No semicolon means this declaration probably won’t be read. The text of the stylesheet is 100% css so all syntax applies here. You don’t put the semicolon after the style object keys because that’s a json object that is being interpreted by the vue renderer before it’s applied to the element so the semicolon’s will get added automatically. The stylesheet is interpreted directly as css which is why you can get more advanced css declarations.

The way the stylesheet property is added to the DOM should mean that it impacts the element it is declared on as well. In practice, it seems that this depends on the element itself and other factors I’ve never been able to fully explain. So, it is often safer to put the stylesheet in a container above the level of the element where you need the declarations. Because you can utilize html tags as well, a clean div component can hold the stylesheet as the root component of the widget without adding any additional f7 styling to get in the way.

The stylesheet css is applied before the style object. So, the style object setting will take precendence unless you override that with !important.

Put that all together and here’s a version that works (with a few additions to make the results more visible in the widget editor):

uid: media_demo
props:
  parameterGroups: []
  parameters: []
tags: []
component: div
config:
  stylesheet: >
    .responsive-width {
      height: 100px;
    }

    @media screen and (max-width: 768px) {
      .responsive-width {
        width: 100vw !important;
      }
    }
slots:
  default:
    - component: f7-block
      config:
        style:
          background-color: rgba(228,237,246)
          border-radius: 20px
          width: 35vw
          min-width: 250px
        class:
          - responsive-width
1 Like

this seems to do the trick, much thanks

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