Package com.smartgwt.client.docs

# Interface ContentsEmbeddedComponents

public interface ContentsEmbeddedComponents

### Embedded Components in Contents

Smart GWT's `Layout` and its subclasses provide a powerful layout engine, but some designs are more naturally expressed with CSS — for example, CSS flexbox with `gap` and `flex-wrap`, CSS grid with named `grid-template-areas`, or a page where Smart GWT widgets are interspersed with static HTML such as headings, paragraphs, and images.

Embedded components in contents bridge this gap: you provide an HTML template as `Canvas.contents` (a plain string, as it has always been), and mark slots for Smart GWT widgets using the `scID` attribute on placeholder elements. The CSS in the template controls all layout and sizing; the framework takes care of connecting widgets to the placeholders at draw time.

#### Basic Usage

Place one or more elements with an `scID` attribute in the `Canvas.contents` string. Each `scID` value identifies a child component by name — either a child already present in the `Canvas.children` array (matched by `Canvas.name`), or an `AutoChild` that will be created automatically if the corresponding `*Defaults` / `*Constructor` properties exist on the Canvas.

After the contents HTML is inserted into the DOM at draw time, the framework scans for `scID` placeholders, resolves each one to a child or AutoChild, and connects the widget to the placeholder element via `Canvas.htmlElement` and `Canvas.matchElement`. The widget renders inside the placeholder and sizes itself to match it, so the HTML's CSS rules control all layout and sizing.

#### Example: Mixing HTML and Smart GWT Widgets

The most common use case is a page section that mixes static HTML content (headings, text, images) with Smart GWT widgets:

      isc.Canvas.create({
          width: "100%", height: "100%",
          overflow: "auto",
          contents:
              '<h2>Employee Directory</h2>' +
              '<p>Select a row to see details.</p>' +
              '<div scID="mainGrid"' +
              '     style="height:400px"></div>' +
              '<footer style="margin-top:10px;' +
              '     color:#888">&copy; 2026 Acme</footer>',
          mainGridDefaults: {
              _constructor: "ListGrid",
              autoFetchData: true,
              dataSource: "employees"
          }
      });

The `<h2>`, `<p>`, and `<footer>` are ordinary HTML rendered by the browser. The `mainGrid` AutoChild fills the 400px-tall placeholder. Because the child is `position:relative` inside the content flow, the entire Canvas scrolls naturally when `overflow` is `"auto"`.

As with all AutoChildren, the created component is accessible as an instance property on the parent — in this case, `this.mainGrid`. See `AutoChildren` for details.

#### Example: CSS Flexbox

      isc.Canvas.create({
          width: "100%", height: "100%",
          contents:
              '<div style="display:flex; gap:10px;' +
              '     height:100%">' +
                  '<div scID="mainGrid"' +
                  '     style="flex:1"></div>' +
                  '<div scID="detail"' +
                  '     style="width:300px"></div>' +
              '</div>',
          mainGridDefaults: {
              _constructor: "ListGrid",
              autoFetchData: true,
              dataSource: "employees"
          },
          detailDefaults: {
              _constructor: "DetailViewer",
              dataSource: "employees"
          }
      });

The CSS `flex` rules control the split between the grid and the detail viewer.

#### Example: CSS Grid with Named Areas

CSS Grid's `grid-template-areas` is a particularly natural fit for `scID`, since both use names to identify regions:

      isc.Canvas.create({
          width: "100%", height: "100%",
          contents:
              '<div style="display:grid; height:100%;' +
              '     grid-template-columns: 1fr 300px;' +
              '     grid-template-rows: auto 1fr auto;' +
              '     grid-template-areas:' +
              "     'header header'" +
              "     'grid   detail'" +
              "     'footer footer';" +
              '     gap: 8px">' +
              '<h2 style="grid-area:header;' +
              '     margin:0">Dashboard</h2>' +
              '<div scID="mainGrid"' +
              '     style="grid-area:grid"></div>' +
              '<div scID="detail"' +
              '     style="grid-area:detail"></div>' +
              '<div style="grid-area:footer;' +
              '     text-align:center;' +
              '     color:#888">Status bar</div>' +
              '</div>',
          mainGridDefaults: {
              _constructor: "ListGrid",
              autoFetchData: true,
              dataSource: "employees"
          },
          detailDefaults: {
              _constructor: "DetailViewer",
              dataSource: "employees"
          }
      });

The header and footer are plain HTML; the grid and detail areas are Smart GWT widgets sized by the CSS grid engine.

#### Example: Explicit Children

Instead of AutoChildren, pre-created children can be supplied in the `Canvas.children` array. Each child's `Canvas.name` must match the corresponding `scID`:

      isc.Canvas.create({
          width: "100%", height: "100%",
          contents:
              '<div style="display:flex; gap:10px;' +
              '     height:100%">' +
                  '<div scID="gridArea"' +
                  '     style="flex:1"></div>' +
                  '<div scID="chartArea"' +
                  '     style="flex:1"></div>' +
              '</div>',
          children: [
              isc.ListGrid.create({
                  name: "gridArea",
                  autoDraw: false,
                  dataSource: "employees",
                  autoFetchData: true
              }),
              isc.FacetChart.create({
                  name: "chartArea",
                  autoDraw: false,
                  facets: [{ id: "region" }],
                  dataSource: "employees",
                  autoFetchData: true
              })
          ]
      });

#### How It Works

The framework processes `scID` placeholders during `Canvas.draw()`, between HTML insertion and `drawChildren()`. For each `scID` found in the DOM:

1. The name is resolved to an existing child (by `Canvas.name`) or an AutoChild (via Canvas.addAutoChild()). If neither resolves, a warning is logged and the placeholder is left empty.
2. The child is connected to the placeholder element with `Canvas.htmlElement` set to the placeholder, `Canvas.htmlPosition` set to `"afterBegin"`, and `Canvas.matchElement` set to `true`. This causes the widget to render inside the placeholder and size itself to match.
3. The child draws in the normal `drawChildren()` pass.

Because the child is rendered `position:relative` inside the placeholder, it participates in normal document flow. The placeholder's CSS (width, height, flex, grid-area, etc.) controls the widget's size and position, and `Canvas.persistentMatchElement` ensures the widget tracks the placeholder through subsequent page reflows.

#### Scrolling and Responsive Behavior

Because embedded children are `position:relative` within the contents, they scroll naturally with the rest of the content when `overflow` is set to `"auto"` or `"scroll"`. This is a key difference from Smart GWT's Layout system, which uses absolute positioning internally.

CSS media queries, `flex-wrap`, and other responsive techniques work as expected — when the browser reflows the template (for example, due to a viewport resize), `Canvas.persistentMatchElement` detects the placeholder's new size and automatically resizes the embedded widget to match.

#### Dynamic Contents

`Dynamic contents` (`${}` expressions) can be combined with `scID` placeholders. The `${}` expressions are evaluated first, producing the final HTML string, and then the framework scans the resulting DOM for `scID` attributes. This allows the template itself to be data-driven while still embedding Smart GWT components.

#### Visibility

When an embedded child is hidden (via `Canvas.hide()`, `Canvas.visibleWhen`, etc.), the child's DOM handle becomes invisible but the `scID` placeholder element is unaffected — it retains whatever size and position the CSS template gives it. This follows the existing `Canvas.matchElement` contract: the framework controls the widget; the CSS template controls the placeholder.

If a design requires the placeholder to collapse when the child is hidden (for example, so that flex siblings expand to fill the vacated space), this can be achieved by toggling the placeholder's own CSS from application code — for instance, setting `display:none` on the placeholder in a `Canvas.visibilityChanged()` override.

#### Redraw Behavior

When a Canvas with `scID` placeholders is redrawn (e.g., via `Canvas.setContents()` or `Canvas.markForRedraw()`), the framework preserves embedded children using a detach-and-reattach strategy:

1. Each embedded child's DOM handle is detached from its placeholder (without destroying the widget).
2. The contents HTML is replaced in the DOM.
3. The DOM is re-scanned for `scID` placeholders.
4. Children already connected to an `scID` are reattached to the corresponding new placeholder element without re-resolving.

If a placeholder that previously existed is absent after redraw, the corresponding child is `cleared` but not destroyed, allowing it to be reconnected if the placeholder reappears in a subsequent redraw. Conversely, if a new `scID` appears that was not in the previous contents, `Canvas.resolveContentsComponent()` is called to resolve it, including AutoChild creation if applicable.

For `Canvas.htmlPosition` variants where the child is absolutely positioned over (rather than inside) the placeholder, a `clear()` / `draw()` cycle is used instead of detach/reattach, because the child's position depends on coordinates that must be recalculated.

#### Layout Interaction

When `scID` placeholders are used in a `Layout` or its subclasses (VLayout, HLayout, etc.), embedded children are positioned by the CSS template, not by the Layout engine. These children are part of the `Canvas.children` array but are not added as `Layout.members`, so `Layout.layoutChildren()` does not attempt to size or position them.

#### Restrictions

- `scID` resolution is local to the owning Canvas. A placeholder cannot reference a widget that is not a child or AutoChild of the Canvas whose contents contains the placeholder.
- A given `scID` value must be unique within a single Canvas's contents.
- The placeholder element should be a block-level element (typically a `<div>`). Using inline elements may produce unexpected sizing behavior.
- Embedded children should not also be added as `Layout.members` of the same Canvas.
- Embedded children are normal `Canvas.children` and follow standard child lifecycle — they are destroyed when the parent is `destroyed`.

See Also:
  - `Canvas.getContents()`
  - `Canvas.getHtmlElement()`
  - `Canvas.getMatchElement()`
  - `com.smartgwt.client.docs.AutoChildren`
  - `Canvas.resolveContentsComponent(java.lang.String, com.google.gwt.dom.client.Element)`
  - `Canvas.contentsComponentConnected(com.smartgwt.client.widgets.Canvas, java.lang.String, com.google.gwt.dom.client.Element)`
  - `Canvas.getContentsComponentDefaults()`