Starcounter
HomeDownloadDocsCommunity
2.3.1
2.3.1
  • Starcounter Documentation
  • Getting Started
  • Starcounter
    • Collapsing the Stack
      • Complexity and Scalability Tradeoff
      • The Future of Micro-Services
      • 10 Benefits of Collapsing the Stack
    • Integrated Database and Web Server
  • Hello World - Tutorial
    • Create a Database Class
    • Create a Real Time UI
    • First Interactive UI
    • Computed Properties
    • Expense Tracker
    • Cancel and Delete
    • The Next Step
  • Guides
    • Database
      • Database Classes
      • Data manipulation
      • Object Identity and Object References
      • Querying with SQL
      • Data Types
      • Relations
      • Inheritance
      • Sharing data
      • Database Configuration
      • Comparing Database Objects
      • Referential Integrity and Constraints
    • SQL
      • Identifiers
      • Path Expressions
      • Data operators
      • Joins
      • Aggregates
      • Comparisons and Logical Operators
      • Sorting
      • Fetch
      • Offset Key
      • Indexes
      • Literals
      • Query Plan Hints
      • Reserved words
      • Query for Database Classes
      • SQL Isolation Between Applications
    • Transactions
      • Short-Running Transactions
      • Long running transactions
      • Using Transactions
      • Running Background Jobs
      • Commit Hooks
    • Typed JSON
      • JSON-by-example
      • Code-Behind
      • Data Bindings
      • Callback Methods
      • Responding with JSON
      • Accepting JSON in Requests
      • Primitive Arrays and Single Value Types
      • Typed JSON Internals
    • Blendable Web Apps
      • Starcounter MVVM
      • Palindrom
      • Client-Side Stack
      • Sessions
      • HTML Views
      • App Shell
      • Web Components
      • View Attaching
      • View Composing
      • HTML Compositions
      • HTML Views Blending Guidelines
      • Avoiding CSS conflicts
      • Debugging
    • Network
      • HTTP
      • Internal Self Calls
      • Middleware
      • Anonymous or Substitute Handlers
      • URL Aliases and Redirects
      • Network Gateway
      • Static File Server
      • External HTTP Calls
      • WebSocket
      • Avoiding URI conflicts
      • TCP Sockets
      • UDP Sockets
    • Publishing Apps
    • Working with Starcounter
      • Release Channels
      • Starting and Stopping Apps
      • Administrator Web UI
      • Star CLI
      • StarAdmin CLI
      • StarDump CLI
      • Working in Visual Studio
      • Error Log
      • Using HTTPS on NGINX
      • Using HTTPS on IIS
      • Run Starcounter in Production
      • Weaver
      • Investigating App Crashes
      • Configuration Structure
      • Database Refactoring
      • Using Unload/Reload to Modify Database Schema
      • Kernel Questions and Answers
      • Log Files
  • Cookbook
    • Attach an HTTP Request to an Existing Long-Running Transaction
    • Cookie-Based Authentication
    • Timestamp on Object Creation
    • Creating Strongly Typed JSON Collections
    • Migrating From 2.2 to 2.3+
    • Multiple Pages
    • Icons
    • Proposed Project Structure
    • Acceptance Testing with Selenium
    • Requesting a User to Authenticate
    • How to delete unused tables and columns
Powered by GitBook
On this page
  • Introduction
  • Guideline 1: Separation of Layout and Content
  • Guideline 2: Defining the Content
  • Guideline 3: Attaching the Content to Slots
  • Guideline 4: Create the Layout in declarative-shadow-dom
  • Guideline 5: Apply Styling to Avoid Conflicts and Allow Blending
  • Additional Resources
  1. Guides
  2. Blendable Web Apps

HTML Views Blending Guidelines

PreviousHTML CompositionsNextAvoiding CSS conflicts

Last updated 7 years ago

Introduction

In order to harness the full power of Starcounter, applications should be built to accomodate for complete visual and functional interoperability. To make this process easier for developers, we provide these guidelines for HTML views which, when followed, will allow applications to achieve seamless visual integration with other applications.

To get a technical background, the article covers more of the underlying ideas of what's presented here. It may also be worth to take a look at the following articles:

has to run for the code in these guidelines to work. There are two ways to start CompositionProvider: follow the instructions in the , or, when Starcounter is running, go to http://localhost:8181/#/databases/default/appstore, click on the download button next to CompositionProvider, and click Start at http://localhost:8181/#/databases/yourDatabase. This requirement is temporary.

Guideline 1: Separation of Layout and Content

To make applications look great when running independently while also allowing them to visually blend with other applications, it is beneficial to separate the layout and the content. This is accomplished using the <template is="declarative-shadow-dom"> element.

The basic boilerplate of a Starcounter HTML view, which is created by adding a Starcounter HTML template with dom-bind file in Visual Studio, looks like this:

<link rel="import" href="/sys/polymer/polymer.html">

<template>
    <template is="dom-bind">

    </template>
</template>

To separate the layout and content in this file, the element mentioned above, <template is="declarative-shadow-dom"> should be used. This element should contain the layout of the HTML view while the <template is="dom-bind"> should contain the content. Note that this only applies when using Polymer as a templating engine. When using other frameworks, it will not use dom-bind, although, the principle of separating the layout from the content will stay constant. In code, this is how it looks:

<link rel="import" href="/sys/polymer/polymer.html">

<template>
    <template is="dom-bind">
        <!-- content goes here -->
    </template>
    <template is="declarative-shadow-dom">
        <!-- layout goes here-->
    </template>
</template>

The content are the elements that either contain information for the user, such as <h1>, <span>, and <a>, or elements that create some kind of interaction between the user and the application, such as <button> and <input>.

Keep in mind that the only elements that have to be in the <template is="dom-bind"> are the ones that use Polymer bindings, as denoted with double curly-bracket syntax: {{model.SomeProperty}}.

The content of the HTML view is distributed using a Shadow DOM concept called slots, as explained in guideline 4.

Guideline 2: Defining the Content

When defining the content of a view, it is important to keep in mind that the slotable elements, which are the ones that will be exposed for blending, have to be on the root of the HTML view. Consider the following HTML view:

<template>
    <h1>A Headline</h1>
    <p>Some text for te user to read</p>
    <button>A button to click</button>
</template>

Here, every element is at the root of the document and will be exposed for blending after they are attached to slots and distributed in the Shadow DOM. In some cases, putting every element on the root of the view, like we do in the example above, might not be desired. Then, the goal should still be to place as many elements as possible on the root of the view, especially elements like <img>, <table>, and custom elements that are visually obtrusive and might require blending to create a high level of interoperability.

Additionally, there might be situations where the developer would like to have a higher level of abstraction on some of his or her content. For example, consider this pagination bar:

Here, it would not make sense to break it up into the respective parts because they do not have any real meaning when presented individually. It would rather make sense to put the parent on the root level so that the whole bar is exposed for blending, and not the individual buttons.

Guideline 3: Attaching the Content to Slots

The first slot in a shadow tree, in tree order, whose name is the empty string, is sometimes known as the "default slot".

Text nodes are also distributed in the default slot.

It's not necessary to declare the default slot in the declarative-shadow-dom part of your view. The Starcounter's HTML merger automatically adds a default slot at the bottom of the composition of your view for fallback reasons.

Guideline 4: Create the Layout in declarative-shadow-dom

As outlined in guideline 1, the layout of the HTML view should be included within the <template is="declarative-shadow-dom">.

There is one exception to this. Both slot attributes and declarative-shadow-dom can be omitted if the view only contains non-visual elements or if all elements should be bulked together in the default slot. The latter is rarely the case but may be useful for example for prototyping.

Consider the following HTML view definition:

<link rel="import" href="/sys/palindrom-redirect/palindrom-redirect.html" />

<template>
    <template is="dom-bind">
        <style>
            .people-field {
                display: flex;
                flex-direction: row;
                align-items: baseline;
                margin-bottom: 5px;
            }
            .people-field__label {
                flex: 0 0 75px;
                margin-right: 20px;
            }
            .people-field__control {
                flex: 1 1 75px;
            }
        </style>
        <div class="people-field">
            <div class="people-field__label">
                <label slot="people/first-name-label" class="control-label">First name:</label>
            </div>
            <div class="people-field__control">
                <input slot="people/first-name-control" type="text" value="{{model.FirstName$::change}}" placeholder="First name" class="form-control" />
            </div>
         </div>
    </template>
</template>

To add declarative-shadow-dom to this HTML view, something like this can be done:

<link rel="import" href="/sys/palindrom-redirect/palindrom-redirect.html" />

<template>
    <template is="dom-bind">
        <label slot="people/first-name-label" class="control-label">First name:</label>
        <input slot="people/first-name-control" type="text" value="{{model.FirstName$::change}}" placeholder="First name" class="form-control" />
    </template>
    <template is="declarative-shadow-dom">
        <style>
            .people-field {
                display: flex;
                flex-direction: row;
                align-items: baseline;
                margin-bottom: 5px;
            }
            .people-field__label {
                flex: 0 0 75px;
                margin-right: 20px;
            }
            .people-field__control {
                flex: 1 1 75px;
            }
        </style>

        <div class="people-field">
            <div class="people-field__label">
                <slot name="People/first-name-label"></slot>
            </div>
            <div class="people-field__control">
                <slot name="People/first-name-control"></slot>
            </div>
         </div>
    </template>
</template>

Here, the elements are distributed in the way that the view will look when no blending is applied or when the app is running in standalone mode.

Guideline 5: Apply Styling to Avoid Conflicts and Allow Blending

Regarding styling, there are two ways to make the application easier to visually integrate with other apps:

  1. Keep styling that will affect the layout inside the declarative-shadow-dom.

  2. To avoid writing the same Shadow DOM CSS on different pages, it can be imported with the CSS import rule. The syntax for this is <style>@import url("/yourapp/css/style.css");</style>. In the example above it would be done this way:

<link rel="import" href="/sys/palindrom-redirect/palindrom-redirect.html" />

<template>
    <template is="dom-bind">
        <label slot="People/first-name-label" class="control-label">First name:</label>
        <input slot="People/first-name-control" type="text" value="{{model.FirstName$::change}}" placeholder="First name" class="form-control" />
    </template>
    <template is="declarative-shadow-dom">
        <style>
        @import url("/people/css/style.css");
        </style>

        <div class="people-field">
            <div class="people-field__label">
                <slot name="People/first-name-label"></slot>
            </div>
            <div class="people-field__control">
                <slot name="People/first-name-control"></slot>
            </div>
         </div>
    </template>
</template>

Additional Resources

To have better flexibility in blending - to be able to distribute an element individually - the element needs to be assigned to , like <button slot="myapp/submitbutton">Submit</button>. Such an element could be distributed via <slot name="myapp/submitbutton"></slot> in the Shadow DOM. Prefix slot names with the app name, to avoid collisions.

When no slot name is provided for an element it will be distributed in : <slot></slot>.

Use explicit slot names instead of relying on the default slot. The solution owner can remove the default slot from a view composition with the . As a result, all elements from the view that don't have a slot attribute are not rendered.

The is used to distribute the content in the Shadow DOM: <slot name="appname/elementname"></slot>.

Prefix all class names with the name of the app, as outlined in .

To find more information about creating HTML View definitions, take a look at and the which fully adheres to these guidelines.

Layout compositions for HTML partials
Unobtrusive styling and composing 3rd party HTML content
HTML partials/includes WebComponents-way
CompositionProvider
README file
named slots
the default slot
CompositionEditor
<slot> element
Avoiding CSS Conflicts
the article linked above
People app