Skip to content

Canvas: Widgets have no Height

What are we learning here?

  • The container of a Widget component do not an explicit height

The second example is an attempt to build a simple flexbox layout and show that here you should use canvas and not a widget component.

The layout should have an area with a fixed height and another area below that takes up the remaining height.

We will create again a completely new application with a CSS file, a HTML template and a canvas component in a new folder:

src/demo/apps/canvas-vs-widget-layout/content.module.css

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
:local(.widget) {
   padding: 20px;
   & h2 {
      text-decoration: underline dotted gray;
   }
   & .arrow {
      opacity: 0.5;
      position: absolute;
      color: red;
   }
   & .left {
      top: 50%;
      transform: translate(0, -100%);
      left: 0;
   }
   & .right {
      top: 50%;
      transform: translate(0, -100%);
      right: 0;
   }
   & .up {
      left: 50%;
      transform: translate(-50%, 0);
      top: 0;
   }
   & .down {
      left: 50%;
      transform: translate(-50%, 0);
      bottom: 0;
   }
}

src/demo/apps/canvas-vs-widget-layout/content.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<h2>Widget have no height!</h2>
<div class="h-100 d-flex flex-column">
   <div class="p-2 flex-grow-0 border border-success">A small header</div>
   <div class="p-2 flex-grow-1 border border-success">
      A bigger section which should take all the rest of the space
   </div>
</div>
<div class="arrow left"><i class="fas fa-chevron-circle-left"></i></div>
<div class="arrow right"><i class="fas fa-chevron-circle-right"></i></div>
<div class="arrow up"><i class="fas fa-chevron-circle-up"></i></div>
<div class="arrow down"><i class="fas fa-chevron-circle-down"></i></div>

src/demo/apps/canvas-vs-widget-layout/content.js

1
2
3
4
5
6
7
8
9
import { Widget } from "@codecoupler/cc-ui";
import template from "./content.html";
import style from "./content.module.css";
export default class extends Widget {
   async start() {
      this.element.innerHTML = template;
      this.element.classList.add(style.widget);
   }
}

src/demo/apps/canvas-vs-widget-layout/index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import { Application } from "@codecoupler/cc-ui";
import Content from "./content.js";
export default class extends Application {
   static defaults = {
      "@codecoupler": {
         panel: {
            panelSize: "640 510",
            headerTitle: "Compare Canvas vs. Widget"
         }
      }
   };
   async start() {
      await this.stage.load(Content);
   }
}

We will load the in our root.js file (just replacing again):

src/root.js

1
2
3
4
5
6
7
import { Component } from "@codecoupler/cc-ui";
import TestApp from "./demo/apps/canvas-vs-widget-layout";
export default class extends Component {
  async start() {
    await this.stage.load(TestApp);
  }
}

If you look into the HTML structure you would expect a layout like this:

┌─────────────────────────┐
│┌───────────────────────┐│
││ A small section       ││
│├───────────────────────┤│
││                       ││
││ A bigger section      ││
││ which should take all ││
││ the rest of the space ││
││                       ││
│└───────────────────────┘│
└─────────────────────────┘

But you get this:

┌─────────────────────────┐
│┌───────────────────────┐│
││ A small section       ││
│├───────────────────────┤│
││ A small section       ││
│└───────────────────────┘│
│                         │
│                         │
│                         │
│                         │
└─────────────────────────┘

This is because the parent element of the widget component has been stretched to full height, but with the property min-height:100%. The height is set to auto. And there is a good reason for that. E.g. if you want to scroll the content or use other libraries that rely on the height of the element automatically adjusting to the content of the widget.

There are some workarounds for this but the most important point is: A Widget is not the right component to create full height and width layout structures. For this case you should use the Canvas component.

Nevertheless, we don't want to deprive you of the possible workarounds for the problem from the second example:

  • Set the parent element to height:100%. For example with: this.$element.css({ height: "100%" });
  • Replace the parent element with the root element of the template (which property height is already set to 100%) using this.replaceElement(template); instead of this.$element.html(template);