Accordion list using oh-toggle items

I would like to create an accordion list of toggles such that a group item is a toggle item which can be selected or, if the accordion chevron is clicked, the accordion opens and the members of the group can be selected individually.

All of this works. My group members appear using an oh-repeater and if I select the toggle for the group item, the toggles are activated for the members whether the accordion is opened or not.

The one thing I can’t sort out is the formatting. The toggle buttons for the group items appear at teh beginning of the next line in the widget (so underneath the title of the toggle item) instead of (as I imagined they would) just to the left of the accordion chevron on the same line as the title.
image

I’m hoping there’s some sort of obscure style property that I can’t find somewhere but I can’t seem to find anyone else who has come across this.

I’d be very grateful for some help.

Widget looks like this

uid: ListTEst4
tags: []
props:
  parameters: []
  parameterGroups: []
timestamp: Dec 6, 2023, 12:02:14 AM
component: f7-block
config:
  title: Accordion Repeater
slots:
  default:
    - component: oh-list
      config:
        virtualList: true
      slots:
        default:
          - component: oh-toggle-item
            config:
              icon: f7:lightbulb
              title: All
              item: UI_All
          - component: oh-repeater
            config:
              fragment: false
              accordionList: true
              for: floor
              sourceType: itemsInGroup
              groupItem: UI_All
              fetchMetadata: widgetOrder
            slots:
              default:
                - component: oh-toggle-item
                  config:
                     title: =loop.floor.label
                     item: =loop.floor.name
                     style:
                      width: 100%
                  slots:
                    accordion:
                      - component: oh-list
                        config: {}
                        slots:
                          default:
                            - component: oh-repeater
                              config:
                                for: room
                                sourceType: itemsInGroup
                                groupItem: =loop.floor.name
                                fetchMetadata: widgetOrder
                              slots:
                                default:
                                  - component: oh-toggle-item
                                    config:
                                      title: =loop.room.label
                                      item: =loop.room.name

Alas, it’s not quite that simple.

The problem is that the oh-toggle-item was never intended to be used as an accordion item as well, so its structure actually interferes a little bit with the accordion setup. You could wrestle the toggle switch on to the same line with some brute force css, but it would actually wind up to the right of the chevron with several other stylistic issues as well.

The best course of action here is actually just to make your own toggle item from a base f7-list-item and an oh-toggle. That gives you control over the “slot” where the toggle appears which is the problem with the structure of the oh-toggle item. The only wrinkle with switching over to an f7-list-item is that you need to add in the f7-accordion-content component explicitly in the default slot of the item. Then, stylistically, you probably want the oh-toggle in the inner slot so it si on the left side of the chevron and then I’d add in just a little space so it isn’t right up against the chevron.

So, instead of the oh-toggle-item child of the repeater, you probably want something like this:

- component: f7-list-item
  config:
    title: =loop.floor.label
    accordionItem: true
  slots:
    inner:
      - component: oh-toggle
        config:
          item: =loop.floor.name
          style:
            margin-right: 10px
    default:
      - component: f7-accordion-content
        slots:
          default:
...rest of widget starting at oh-list

It never is:^)

I wondered if that might be the case - that the toggle was not designed to be part of an accordion. That’s a pity really because for group items it makes perfect sense to be able to have the group toggle all the member items beneath it on or off. But looking (briefly) at the f7 docs it seems the problem lies there.

I had also thought that perhaps, as you have said, the workaround would be to create my own toggle widget that I could use in an accordion. That looked a bit daunting though and was not a project to start on at midnight last night.

I’ve created dashboards in Node Red before using Vuetify but I am new to custom widgets, f7 and yaml. You have doubtless saved me countless hours of trial, error and frustration. I’ll try to put your suggestion into practice and if I can get a good working example going I’ll post it back to the community and hopefully save others some time.

Thanks again for your input. Where would this community be without you?

Well I’ve finally had chance to play around with that idea Justin and it works… but it doesn’t. I’ve been scratching my head trying to figure out a solution.

The problem is I would like to be able to click on the toggle in order to select underlying items without actually opening up the accordion. Unfortunately, clicking on the toggle or indeed anywhere on the floor level item opens up the accordion of room items. There seems to be no way to disengage the click from the open action unless you dig right into f7 and trap events, which I’m not sure we can do in the Openhab UI.

Also for some reason, with the toggle in the inner slot it seems that I can’t click to toggle any more. The floor level toggle only works by carefully selecting the actual orange button and dragging it to one side or the other… and it still opens or closes the accordion.

I’m trying to play around with a grid layout to separate the list of floors accordion from the related toggle to see if that works but it’s taking me some time

Right…I didn’t think of that. You do have to have the toggle outside the item link container. You can get that effect pretty easily too, you just have to tweak a few things. The root-start slot is actually outside the item link container so you can just put your toggle in that slot. That will however, without further styling, just add the toggle above the rest of the list item. For styling then, I would just shorten the list item a little bit and absolutely position the toggle beyond the end of the list item like this:

          - component: f7-list-item
            config:
              title: Title here
              accordionItem: true
              style:
                width: calc(100% - 50px)
              stylesheet: >
                .accordion-item-content {
                  width: calc(100% + 50px);
                }
            slots:
              default:
                - component: f7-accordion-content
                  slots:
                    default:
                      - component: oh-list
                        config:
                          simpleList: true
                        slots:
                          default:
                            - component: oh-toggle-item
                              config:
                                title: Toggle item
                                item: itemName
              root-start:
                - component: oh-toggle
                  config:
                    item: otherItemName
                    style:
                      position: absolute
                      right: -40px
                      top: 6px
1 Like

I can’t tell you how grateful I am to you for the time you are putting into this Justin.
The formatting looks great now
image

I had come up with a similar solution using the grid layout but yours is more elegant and flexible.

I have no clue what you did with the stylesheet property so I couldn’t begin to replicate it but it works. I found I needed 55px to make the toggles line up correctly - no idea why. I tried to find another way playing with widths and margins but haven’t found one yet. That’s not a high priority.

Many many thanks

For the benefit of others, here is the working widget

uid: ListTest11
tags: []
props:
  parameters: []
  parameterGroups: []
timestamp: Jan 10, 2024, 8:32:53 PM
component: f7-block
config:
  title: Accordion Repeater
slots:
  default:
    - component: oh-list
      config:
        virtualList: true
      slots:
        default:
          - component: oh-toggle-item
            config:
              icon: f7:lightbulb
              title: All
              item: UI_All
          - component: oh-repeater
            config:
              fragment: false
              accordionList: true
              for: floor
              sourceType: itemsInGroup
              groupItem: UI_All
              fetchMetadata: widgetOrder
            slots:
              default:
                - component: f7-list-item
                  config:
                    title: =loop.floor.label
                    accordionItem: true
                    style:
                      width: calc(100% - 50px)
                    stylesheet: >
                      .accordion-item-content {
                      width: calc(100% + 55px);
                      }
                  slots:
                    default:
                      - component: f7-accordion-content
                        slots:
                          default:
                            - component: oh-list
                              slots:
                                default:
                                  - component: oh-repeater
                                    config:
                                      for: room
                                      sourceType: itemsInGroup
                                      groupItem: =loop.floor.name
                                      fetchMetadata: widgetOrder
                                    slots:
                                      default:
                                        - component: oh-toggle-item
                                          config:
                                            style:
                                              margin-left: 20px
                                              margin-right: 0px
                                            title: =loop.room.label
                                            item: =loop.room.name
                    root-start:
                      - component: oh-toggle
                        config:
                          item: =loop.floor.name
                          style:
                            position: absolute
                            right: -40px
                            top: 6px

For those who might want to use this in their own widgets, below is an updated version with three levels of grouping. I use this to be able to switch on and off Whole House, Floor and Room level items in groups without necessarily needing to open up the whole group and switch each item individually.

I moved the toggles to the left of the list so that I can create indented formatting which makes it easier to read, so it now looks like this:
Screenshot 2024-02-16 at 13-53-02 openHAB

Code is below

uid: Expanding_List_Props
tags: []
props:
  parameters:
    - description: Display name of the top group
      label: Top group name
      name: groupname
      required: false
      type: TEXT
    - context: item
      description: Top group
      label: Whole house
      name: groupItem
      required: true
      type: TEXT
  parameterGroups: []
timestamp: Jan 28, 2024, 7:20:04 PM
component: f7-block
config:
  title: Accordion Repeater
slots:
  default:
    - component: oh-list
      config:
        accordionList: true
        virtualList: true
      slots:
        default:
          - component: f7-list-item
            config:
              accordionItem: true
              style:
                margin-left: 40px
                width: calc(100% - 40px)
              title: =[props.groupname]
            slots:
              default:
                - component: f7-accordion-content
                  slots:
                    default:
                      - component: oh-list
                        config:
                          virtualList: true
                        slots:
                          default:
                            - component: oh-repeater
                              config:
                                accordionList: true
                                fetchMetadata: widgetOrder
                                for: floor
                                fragment: false
                                groupItem: =[props.groupItem]
                                sourceType: itemsInGroup
                              slots:
                                default:
                                  - component: f7-list-item
                                    config:
                                      accordionItem: true
                                      style:
                                        margin-left: 50px
                                        width: calc(100% - 50px)
                                      title: =loop.floor.label
                                    slots:
                                      default:
                                        - component: f7-accordion-content
                                          slots:
                                            default:
                                              - component: oh-list
                                                slots:
                                                  default:
                                                    - component: oh-repeater
                                                      config:
                                                        fetchMetadata: widgetOrder
                                                        for: room
                                                        groupItem: =loop.floor.name
                                                        sourceType: itemsInGroup
                                                      slots:
                                                        default:
                                                          - component: f7-list-item
                                                            config:
                                                              style:
                                                                margin-left: 50px
                                                                margin-right: 0px
                                                                width: calc(100% - 50px)
                                                              title: =loop.room.label
                                                            slots:
                                                              root-start:
                                                                - component: oh-toggle
                                                                  config:
                                                                    item: =loop.room.name
                                                                    style:
                                                                      left: -35px
                                                                      position: absolute
                                                                      top: 6px
                                      root-start:
                                        - component: oh-toggle
                                          config:
                                            item: =loop.floor.name
                                            style:
                                              left: -35px
                                              position: absolute
                                              top: 6px
              root-start:
                - component: oh-toggle
                  config:
                    item: UI_All
                    style:
                      left: -35px
                      position: absolute
                      top: 6px

2 Likes