Customizing oh-cell

A lot of CSS features have been added to standard widgets over time. To make use of these new features I wanted to re-create my own home oh-page and like to ask our CSS experts here, if it is now possible to customize an oh-cell in terms of

  • font: size, color, weight (header, title, subtitle, label, footer)
  • icon: size, color
  • background-color

In particular background color is quite tricky as expressions seem to interfere with background logic which also controls background color and opacity.
If you could simply opst some working examples I’d be happy and can work from there.

Thanks in advance.

The oh-cell is one of the most complex of the compound components. As such it still does not accept a style object because there are so many different sub-components it wold be nearly impossible to put in a style object that addresses each one. Your best bet for styling a cell remains using a stylesheet and the browser inspection function or the cell file itself to work out which classes impact the piece you want to change.

uid: cell_style
props:
  parameterGroups: []
  parameters: []
tags: []
component: oh-cell
config:
  header: Header
  title: Title
  subtitle: Subtitle
  icon: f7:airplane
  footer: footer
  stylesheet: |
    .cell-background {
      background: linear-gradient(to bottom right, red, gold);
    }

    .header-text {
      color: yellow;
    }

    .header-icon {
      color: #F0F8FF;
    }

    .item-footer {
      font-weight: 900;
    }
slots:
  default:
    - component: oh-button
      config:
        text: Button

The cell background logic is as follows:

  1. If there are components in the cell background slot show those, otherwise check for a trendline.
  2. If there is a trendItem configured then draw the graph.
  3. If neither of those are true then create a div element with the cell-background class.
  4. If the cell color property is set and the cell on property is true (defaults to true if not sepcifcied) then add the appropriate f7 background color class (e.g., bg-green) to the div as well, which will cause the f7 library to style that div background with the default f7 color of that name.

So to control the background of the cell (when closed) with css is not difficult you just have to make sure that you don’t have any components in the background slot, have not configured a trendline item, and have not set the cell color or the on properties. Basically don’t add any of these other properties and you can select the cell-background element and give it whatever background you want.

If you want to have background components, or a trendline and still control the background of the cell with css it does get more complicated because finding the correct selector can be tricky.

The only other issue with this approach is that, of course, the stylesheet is not dynamic. You can’t use expressions so if you want dynamic styles then you have to use css variables with are set in a style object separate from the stylesheet. The problem here, as I said above, is that the oh-cell doesn’t even process a style object so you can’t set the variables there. In this case you would need to wrap your cell component in some other component (a simple div would be the most sensible) and set the variables there.

uid: cell_style
props:
  parameterGroups: []
  parameters: []
tags: []
component: div
config:
  style:
    --my-cell-background-primary: =(items.SomeItem.state == 'ON')?('red'):('midnightblue')
slots:
  default:
    - component: oh-cell
      config:
        header: Header
        title: Title
        subtitle: Subtitle
        icon: f7:airplane
        footer: footer
        stylesheet: |
          .cell-background {
            background: linear-gradient(to bottom right, var(--my-cell-background-primary), gold);
          }

          .header-text {
            color: yellow;
          }

          .header-icon {
            color: #F0F8FF;
          }

          .item-footer {
            font-weight: 900;
          }
2 Likes

A million times thank you for this lesson! This makes customizing a lot easier.

All oh-cells on my home oh-page will look almost identically. This means I add all static changes such as font-size, icon-size, etc to the page config section and dynamic changes need to be wrapped in a div element if they cannot be applied directly in an oh-cell.

Where can I get more details about the capabilities of oh-cell? stateStyle, headerBadge and so on are not documented and not available in the MainUI helper menu.

You can always go to the link I posted above for the vue definition of the oh-cell. You don’t have to be 100% familiar with vue to still get something out of looking through that. For example, just searching that page for ‘config.’ will show you all the configuration options that you could use in the widget editor and give you at least an idea of how they are used. (Unless there’s an error such as the one I just saw with headerBadgeColor while looking at the cell page…I’ve put in a quick pr to fix it so that will also work soon).

ok. I tried to apply the lernings. Some stuff I found out, but struggling e.g. with size of the icon.
I assume there is no other way than to add a new oh-icon control to the background slot?

It is quite possible to use css to change the size of the icon. We first use the browser or the vue file to find the most appropriate class. In this case, there is a header-icon class that is applied directly to the oh-icon component that renders the cell’s icon so we’ll use that.

If you’re using an f7 icon. Those are actually just a special font. So to change the size of the icon we have to use the font-size css property:

component: oh-cell
config:
  header: Header
  icon: f7:ant
  stylesheet: |
    .header-icon {
      font-size: 52px;
    }

image
But that wasn’t quite enough. With css, order matters. In this case, the oh-icon itself applies a font-size setting, and that comes after the class applies its settings, so the icon value takes precedence. We have to tell css that it’s can’t override our setting with the !important keyword:

component: oh-cell
config:
  header: Header
  icon: f7:ant
  stylesheet: |
    .header-icon {
      font-size: 52px !important;
    }

image
Now, our icon is bigger, but it’s overrunning its space so we have to make its space larger too.

component: oh-cell
config:
  header: Header
  title: Title
  icon: f7:ant
  stylesheet: |
    .header-icon {
      font-size: 52px !important;
      width: 52px !important;
      height: 52px !important;
    }

image
If you’re using one of the built-in OH icons, then all the same reasoning applies, but it’s not a font it’s just an image so you can skip the font-size step.

component: oh-cell
config:
  header: Header
  title: Title
  icon: oh:vacation
  stylesheet: |
    .header-icon {
      width: 52px !important;
      height: 52px !important;
    }

image

1 Like

I was at that point but !important didn’t come into my mind :man_facepalming:
Thank you very much again.

Hi Justin,
I was able to find all properties to customize oh-cell.
One thing I was struggling with is to change the background color of an opened card. Are you able to identify the stylesheet and property I need to change?

That will be the cell contents class, if I recall:

stylesheet: >
  .cell-contents {
    background: blue;
  }

Yes, that changes both cell and card opened.

I just found .card-expandable. and card-opened but that didnot change the opened card only.
So probably this isn’t achievable.

Sorry, I didn’t realize that you wanted the background only when the card is opened. That’s only a little trickier. You are right that it involves the card-opened class, but that class applies to the cell element and not the contents element. So, your css selector needs to include both of those with the descendant of relationship (which is the easiest…just a space).

stylesheet: >
  .card-opened .cell-contents {
    background: blue;
  }

However, there’s a second trick here, and that is that because the scope of this stylesheet has to include the cell itself (where the card-opened class is applied) you need to use the trick where you use a div container for the cell itself and put this stylesheet in the container:

component: div
config:
  stylesheet: >
    .card-opened .cell-contents {
      background: blue;
    }
slots:
  default:
    - component: oh-cell
...

Lastly, you will note that the only applies the background when the card is fully opened. If you want to see the background while the card opening animation is also happening then you need the card-opening class and you need to use it the same way as the card-opened class:

component: div
config:
  stylesheet: >
    .card-opening .cell-contents, .card-opened .cell-contents {
      background: blue;
    }
slots:
  default:
    - component: oh-cell
...
1 Like

Wow - I am flashed. Thank you very much again!