# Creating Personal Widgets

# Creating a Widget

You can extend the library of widgets you have at your disposal by creating personal ones, either by yourself, or copy-pasting from examples by the community; then you can reuse them on pages, multiple times if need be, simply configuring their props to your needs. To add a new personal widget, as an admin, go to Developer Tools > Widgets, then use the '+' button to create a new one.

The view features a code (YAML) editor and a live preview, you can change the orientation with the button in the center of the bottom toolbar.

WARNING

Don't forget to change the uid right away because you won't be able to alter it afterwards.

Sometimes the live preview will fail to update, you may want to hit the Redraw button or Ctrl-R/Cmd-R regularly when designing your widget.

To actually see how the config sheet would look like, and specify props for your widget for the live preview, click on Set props (Ctrl-P) and configure them as needed.

After saving the widget, you will have it as an option (under "Personal widgets") to add it to a layout page, or display in a modal like a popover, or use it as the default representation of an item.

Note that to add a personal widget to a page or other widget, use the special widget:<uid> syntax for the component type to specify "use this personal widget here". The config options are the widget's props and the value you wish to assign to each:

component: widget:widget_0a26c10a4d
config:
  prop1: Test
  item: Color1

# Widget Structure

The custom widget feature has been designed to be very accessible and users do not require a detailed understanding of webdesign to get started. It may be useful even to beginning users, however, to have a basic understanding of the logical flow of the system. Custom widgets are defined using YAML which is a human readable data format that easily converts back and forth from JSON, a text-based data format widely-used in web applications. MainUI uses the JSON data to populate templates built using Vue, a language for dynamically building HTML, taking advantage of the pre-made components available from the Framework7 (F7) (opens new window) library. 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.

# Component config

Nearly every component will have some aspect that needs to be specified or modified to suit a specific need. This is accomplished by adding a config section to the component's YAML.

- component: oh-toggle
  config:
    item: mySwitchItem

Some of the available configuration parameters are specific to a certain component while others, such as visible or class are available in most components. Widget expressions can be used to dynamically set configuration parameters depending on dynamic, changing data, e.g. Item states.

# Component slots

HTML pages are hierarchically nested. In order to reflect this structure in the YAML most components will have slots. To define a component that must be a child (nested inside) of another component you indent the YAML of the child component within one of the defined slots of the first one.

- component: oh-list
  slots:
    default:
      - component: oh-list-item

In most cases a component will have a default slot that is the most appropriate slot to use for simple construction. Some of the components will have more specific slots such as header or content which are rarely used.

# Components

In the custom widget system there are many options for different components to include. Where each component comes from determines many of the options available for configuration and styling.

# openHAB components

The most common type of component in most widgets will be the openHAB (OH) family of widgets. These are modified versions of the F7 library of components. The modifications include themeing to match the MainUI color and style themes and functionality that provides direct interaction with OH features such as Items. A basic description of each of these components and the their capabilities (with examples) can be found on the Component Reference page. Because most of the OH specific components are built on top of the F7 components, the documentation of the F7 components (opens new window) is often useful for users wishing to understand more about the OH components as well.

There are several subsets of OH components, each with different uses and strengths:

  • Basic: a component which can be placed within other components (e.g., oh-slider)
  • Standalone Card: a component placed inside a container styled to look like a separate visual element (e.g., oh-slider-card)
  • Cell: a container styled to look like a separate visual element which will expand to show the component when clicked (e.g., oh-slider-cell)
  • List Item: a component placed inside a list type container meant only to be displayed as part of a list and which will not display properly on its own (e.g., oh-slider-item)
  • Specialized components: many of the available page types in the MainUI (e.g., chart pages) have their own series of specialized components

# F7 components

In addition to being the basis for the OH components, the F7 components themselves are available as options in the widget editor. As a general rule, the F7 components will have more configuration and style flexibility than their OH counterparts. So, their use is recommended when there is something about the component that needs to be configured in a way different than what is set in the OH version. Of course, the F7 components do not have the OH specific functions available, so while they can have values based on Items using the widget expression system, they cannot easily be used to trigger rules, update Items or variables, etc.

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). These components are therefore useful as fundamental building-blocks of widget or page. The list components f7-list-item and f7-list-item-row can often be useful as well given the flexibility they provide for complex structure inside a list.

Any of the OH components that allow widget actions include easy configuration for using some other widget as a popup or popover. If, however, there is need for the popup or popover to be built-in with a single widget (e.g., to add a widget to the marketplace (opens new window) that includes a popup or popover), the f7-popup and f7-popover component can be used and the open or closed status of that modal object controlled by the popupOpen, popupClose, popoverOpen, and popoverClose properties available in many of the other f7 components and their OH derivates.

- component: f7-card
  config:
    title: Popup Card
  slots:
    default:
      - component: oh-link
        config:
          text: Open the popup
          popupOpen: .demo-pop
      - component: f7-popup
        config:
          class: demo-pop
        slots:
          default:
            - component: oh-button
              config:
                text: Close it again
                popupClose: .demo-pop

# Label and Content

There are two special components that are not derived from any other specific library, the Label and the Content component. These two are similar in their simplicity of configuration, primarily taking only a text property (which can be a widget expression).

The Label component renders the value given by the text property inside it's own <div> element. For example:

- component: f7-row
  config:
    class: fancy-row
  slots:
    default:
      - component: Label
        config:
          text: Label text here

renders in the page HTML as:

<div class="row fancy-row">
  <div>Label text here</div>
</div>

Because of this, the Label component also accepts class and style configurations which are applied to the <div>. Label components are often used extensively in compound widgets with several other components to place informative text. However, because of the <div> container, there are times and situations where the Label component can cause placement/alignment issues or even configuration issues if the parent element is not compatible with having a <div> container as a child.

In contrast, the Content component renders the value given by the text property without any additional container. For example:

- component: f7-row
  config:
    class: fancy-row
  slots:
    default:
      - component: Content
        config:
          text: Content text here

renders in the page HTML as:

<div class="row fancy-row">Content text here</div>

With no container, there is no possibility to add class or style configuration to the Content component.

# HTML components

The custom widget system can also be used to build HTML more directly. The component property can also be set to any recognized HTML tag. When used in this manner, the component accepts any configuration paramaters that can be passed to the tag as HTML attributes (including, of course, class and style). There is an additional configuration parameter, content which allows for content text to be included in the tag.

HTML components also accept a default slot which will render a child component inside the tag.

# HTML component examples

The widget YAML:

- component: div
  config:
    content: Make this text bold
    style:
        font-weight: bold

Renders to the HTML:

<div style="font-weight: bold;">Make this text bold</div>

To put more complex HTML hierarchies, use the component's default slot:

- component: div
  config:
    style:
      font-style: italic
  slots:
    default:
      - component: Content
        config:
          text: "This text starts with italics "
      - component: span
        config:
          content: but then becomes BOLD!
          style:
            font-weight: bold

Renders to the HTML:

<div style="font-style: italic;">
  This text starts with italics <span style="font-weight: bold;">but then becomes BOLD!</span>
</div>

# Styling

Personal widgets very likely require some customized styling using CSS.

Please read CSS for Pages & Widgets to learn more about using CSS.