Using Web Components with Angular

We are happy to announce that with the release of Smart HTML Elements ver. 4.1.0, we added "Using with Angular" example for each web component. These Angular examples are available in the Demos section and will help you to use our Web Components in your current or future Angular projects. The source code is included in the download package and can be found in the demos/angular/ folder. The full list of changes in ver.4.1.0 can be found here:

Data Grid Angular Demo: Grid with Angular

Leave a comment

Smart HTML Elements v4.0.0 Release

Smart HTML Elements v4.0.0 Release, Aug-01-2019

What's New:

  • Gantt Chart Web Component
  • File Upload Web Component
  • DropDownButton Web Component
  • Sortable Web Component
  • Color Panel Web Component
  • Color Picker Web Component
  • Query Builder Web Component
  • Validator Web Component
  • New Button styles
  • New Grid Demos

What's Fixed:

  • Fixed an issue in the Grid about Cells Selection when there are frozen rows.
  • Fixed an issue in the Grid about Cells Selection when there is checkbox selection column.
  • Fixed an issue in the Grid about Cells Editing when the column's template is 'checkBox' and the editor is 'input'.
  • Fixed an issue in the Grid about Cells Selection Focus when user clicks outside the Grid, the Focus stays in the Grid.
  • Fixed an issue in the Grid about the rendering, when the columnHeight property is changed dynamically.
  • Fixed an issue in the Grid about the rendering of Row Headers when Alternation is applied.
  • Fixed an issue in the Grid about Row/Col resizing and Selection. Selection is not applied when you start resizing a row or column.
  • Fixed an issue in the Grid about the columnHeader.visible property when it is changed dynamically.
  • Fixed an issue in the Grid about header and footer templates. No effect when set.
  • Fixed an issue in the Grid about the columnWidth property when it is changed dynamically.
  • Fixed an issue in the Grid about the showTooltips property when it is changed dynamically.
  • Fixed an issue in the Grid about the showRowNumber and showRowHeader properties when changed dynamically.
  • Fixed an issue in the Grid about the showResizeTooltips property when it is changed dynamically.
  • Fixed an issue in the Grid about the horizontal scrolling when 'template' is applied to a column.
  • Fixed an issue in the Grid about the showColumnIcon property when the property is changed dynamically.
  • Fixed an issue in the Grid about the showColumnDescriptionButton property when the property is changed dynamically.
  • Fixed an issue in the Grid about the showSortColumnBackground property when the property is changed dynamically.
  • Fixed an issue in the Grid about the showFilterColumnBackground property when the property is changed dynamically.
  • Fixed an issue in the Grid about the Filtering when the Grid has frozen rows, the rows that did not match the filter were not rendered correctly.
  • Fixed an issue in the Grid about the showVerticalScrollBarOnFixedColumns property when it is changed dynamically.
  • Fixed an issue in the Grid about the allowColumnSortButtonAnimation when the property is changed dynamically.
  • Fixed an issue in the Grid about the sorting of boolean columns when the dataType is set to 'bool', not to 'boolean'.
  • Fixed an issue in the Grid about the ensureVisible method and keyboard navigation when there are frozen rows and columns.
  • Fixed an issue in the Grid about the alternation of rows. The alternationEnd was not taken into account.
HTML Elements, Smart Grid, Web Components

Leave a comment

DockingLayout Web Component with Angular

Using Smart.DockingLayout Web Component in Angular application

This post shows how to use the DockingLayout component with Angular and how easy the integration is.


In the app.component.html, we add the smart-docking-layout tag.
<smart-docking-layout [layout]="layout"></smart-docking-layout>  


To make Angular work with Web Components, we add the CUSTOM_ELEMENTS_SCHEMA to the app module and import the Smart Elements

 import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';  
 import { BrowserModule } from '@angular/platform-browser';  
 import { FormsModule } from '@angular/forms';  
 import { AppComponent } from './app.component';  
 import '@smarthtmlelements/smart-elements/source/smart.elements.js';  
   declarations: [AppComponent],  
   imports: [BrowserModule, FormsModule],  
   providers: [],  
   bootstrap: [AppComponent]  
 export class AppModule { }  


Below, we put the Docking Layout component's settings.
import { Component, ViewChild, AfterViewInit } from '@angular/core';  
 import { setTimeout } from 'timers';  
   selector: 'app-root',  
   templateUrl: './app.component.html',  
   styleUrls: ['app.component.css']  
 export class AppComponent implements AfterViewInit {  
   layout: any = [  
       type: 'LayoutGroup',  
       orientation: 'horizontal',  
       items: [  
           id: 'item0',  
           label: 'Tabs 0',  
           autoHide: true,  
           autoHidePosition: 'left',  
           tabPosition: 'bottom',  
           items: [{  
             label: 'Tab A',  
             selected: true,  
             content: 'What is Lorem Ipsum?\n' +  
               'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of' + 'type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in ' + 'the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.\n' +  
               'Why do we use it?\n' +  
               'It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal ' + 'distribution of letters, as opposed to using \'Content here, content here\', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their' + 'default model text, and a search for \'lorem ipsum\' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on ' + 'purpose (injected humour and the like).'  
           type: 'LayoutGroup',  
           items: [  
               tabPosition: 'bottom',  
               type: 'LayoutPanel',  
               id: 'tabPanel',  
               label: 'Input',  
               items: [{  
                 label: 'TextBox Tab',  
                 content: '<smart-multiline-text-box id="multiLine">Write more text here ...</smart-multiline-text-box>'  
                 label: 'Slider Tab',  
                 content: '<smart-slider id="slider"></smart-slider>'  
               size: '50%'  
               type: 'LayoutPanel',  
               label: 'Output',  
               items: [  
                   id: 'outputTab',  
                   label: 'Output',  
                   headerPosition: 'none',  
                   content: 'Write more text here ...'  
           orientation: 'vertical'  
   ngAfterViewInit(): void {  
     document.readyState === 'complete' ? init() : window.onload = init;  
     function init() {  
       document.getElementById('tabPanel').addEventListener('change', (event: any) => {  
         if ( instanceof window['Smart'].Slider) {  
           document.getElementById('outputTab').innerHTML = event.detail.value;  
         else if ( instanceof window['Smart'].MultilineTextBox) {  
           document.getElementById('outputTab').innerHTML =;  
         else if ( === 'Smart-TABS') {  
           const selectedTabItem ='smart-tab-item')[];  
           if (selectedTabItem === undefined) {  
           if (selectedTabItem.label.toLowerCase().indexOf('slider') > -1) {  
             document.getElementById('outputTab').innerHTML = selectedTabItem.querySelector('smart-slider').value;  
           else if (selectedTabItem.label.toLowerCase().indexOf('textbox') > -1) {  
             document.getElementById('outputTab').innerHTML = selectedTabItem.querySelector('smart-multiline-text-box').value;  

Live Example in Stackblitz:

Angular, HTML Elements, Javascript, Web Components
, , , , , , ,

Leave a comment

Define a Custom Element

In this post, we will show you how to define a Custom Element with Smart Framework. We will create a Material Color Picker custom element.

1. Define the Custom Element. To define a new custom element with Smart Framework, we need to call the Smart function with two parameters - the tag name and the Class with the logic.

Smart('smart-colors', class SmartColors extends Smart.BaseElement {  

2. Smart Framework gives us useful things like Templates, Data Binding, Typed Properties, Lifecycle callbacks, Event Handling. Read more about this In our Custom Element, we will use some of these features. We will use the 'ready' lifecycle callback. It is invoked once, when the element is attached for first time. We use this function to create and initialize the custom element. The 'properties' definition includes a property called 'color'. This property has default value - '#fff' and its type is 'string'. This means that when you try to set a 'bool', 'date', 'numeric' value, the element will throw an error with 'Invalid property type'. To raise the 'change' event, we use the '$.fireEvent' method.

3. The full code of our custom element is below
  // Define Custom Element
Smart('smart-colors', class SmartColors extends Smart.BaseElement {  
  // Declare properties
  static get properties() {  
    return {
           value: '#fff',
           type: 'string'
  // Ready is called when the element is in the DOM.
  ready () {
    const that = this;
  // Renders the Color Panel.
  _renderGrid() {
    const that = this;
    const labelsAndPaletteContainer = document.createElement('div');


    labelsAndPaletteContainer.classList = 'smart-labels-and-palette'
  // Rneders all colors.
  _renderColorPalette() {
    const that = this;
    const colorsArray = [
      ['#ffebee', '#ffcdd2', '#ef9a9a', '#e57373', '#ef5350', '#f44336', '#e53935', '#d32f2f', '#c62828', '#b71c1c', '#ff8a80', '#ff5252', '#ff1744', '#d50000'],
      ['#fce4ec', '#f8bbd0', '#f48fb1', '#f06292', '#ec407a', '#e91e63', '#d81b60', '#c2185b', '#ad1457', '#880e4f', '#ff80ab', '#ff4081', '#f50057', '#c51162'],
      ['#f3e5f5', '#e1bee7', '#ce93d8', '#ba68c8', '#ab47bc', '#9c27b0', '#8e24aa', '#7b1fa2', '#6a1b9a', '#4a148c', '#ea80fc', '#e040fb', '#d500f9', '#aa00ff'],
      ['#ede7f6', '#d1c4e9', '#b39ddb', '#9575cd', '#7e57c2', '#673ab7', '#5e35b1', '#512da8', '#4527a0', '#311b92', '#b388ff', '#7c4dff', '#651fff', '#6200ea'],
      ['#e8eaf6', '#c5cae9', '#9fa8da', '#7986cb', '#5c6bc0', '#3f51b5', '#3949ab', '#303f9f', '#283593', '#1a237e', '#8c9eff', '#536dfe', '#3d5afe', '#304ffe'],
      ['#e3f2fd', '#bbdefb', '#90caf9', '#64b5f6', '#42a5f5', '#2196f3', '#1e88e5', '#1976d2', '#1565c0', '#0d47a1', '#82b1ff', '#448aff', '#2979ff', '#2962ff'],
      ['#e1f5fe', '#b3e5fc', '#81d4fa', '#4fc3f7', '#29b6f6', '#03a9f4', '#039be5', '#0288d1', '#0277bd', '#01579b', '#80d8ff', '#40c4ff', '#00b0ff', '#0091ea'],
      ['#e0f7fa', '#b2ebf2', '#80deea', '#4dd0e1', '#26c6da', '#00bcd4', '#00acc1', '#0097a7', '#00838f', '#006064', '#84ffff', '#18ffff', '#00e5ff', '#00b8d4'],
      ['#e0f2f1', '#b2dfdb', '#80cbc4', '#4db6ac', '#26a69a', '#009688', '#00897b', '#00796b', '#00695c', '#004d40', '#a7ffeb', '#64ffda', '#1de9b6', '#00bfa5'],
      ['#e8f5e9', '#c8e6c9', '#a5d6a7', '#81c784', '#66bb6a', '#4caf50', '#43a047', '#388e3c', '#2e7d32', '#1b5e20', '#b9f6ca', '#69f0ae', '#00e676', '#00c853'],
      ['#f1f8e9', '#dcedc8', '#c5e1a5', '#aed581', '#9ccc65', '#8bc34a', '#7cb342', '#689f38', '#558b2f', '#33691e', '#ccff90', '#b2ff59', '#76ff03', '#64dd17'],
      ['#f9fbe7', '#f0f4c3', '#e6ee9c', '#dce775', '#d4e157', '#cddc39', '#c0ca33', '#afb42b', '#9e9d24', '#827717', '#f4ff81', '#eeff41', '#c6ff00', '#aeea00'],
      ['#fffde7', '#fff9c4', '#fff59d', '#fff176', '#ffee58', '#ffeb3b', '#fdd835', '#fbc02d', '#f9a825', '#f57f17', '#ffff8d', '#ffff00', '#ffea00', '#ffd600'],
      ['#fff8e1', '#ffecb3', '#ffe082', '#ffd54f', '#ffca28', '#ffc107', '#ffb300', '#ffa000', '#ff8f00', '#ff6f00', '#ffe57f', '#ffd740', '#ffc400', '#ffab00'],
      ['#fff3e0', '#ffe0b2', '#ffcc80', '#ffb74d', '#ffa726', '#ff9800', '#fb8c00', '#f57c00', '#ef6c00', '#e65100', '#ffd180', '#ffab40', '#ff9100', '#ff6d00'],
      ['#fbe9e7', '#ffccbc', '#ffab91', '#ff8a65', '#ff7043', '#ff5722', '#f4511e', '#e64a19', '#d84315', '#bf360c', '#ff9e80', '#ff6e40', '#ff3d00', '#dd2c00'],
      ['#efebe9', '#d7ccc8', '#bcaaa4', '#a1887f', '#8d6e63', '#795548', '#6d4c41', '#5d4037', '#4e342e', '#3e2723'],
      ['#fafafa', '#f5f5f5', '#eeeeee', '#e0e0e0', '#bdbdbd', '#9e9e9e', '#757575', '#616161', '#424242', '#212121'],
      ['#eceff1', '#cfd8dc', '#b0bec5', '#90a4ae', '#78909c', '#607d8b', '#546e7a', '#455a64', '#37474f', '#263238'],
    const paletteContainer = document.createElement('div');

    for (let index = 0, length = colorsArray.length; index < length; index++) {
      const currentRow = colorsArray[index];
      const currentUl = that._renderRow(currentRow, 'smart-color-cell', false);


    paletteContainer.className = 'smart-palette';
    that._paletteContainer = paletteContainer;
  // Renders all shades.
  _renderShades() {
    const that = this;
    const shadesContainer = document.createElement('div');
    const shadesArray = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 'A 100', 'A 200', 'A 400', 'A 700'];
    const shadesRow = that._renderRow(shadesArray, 'smart-shade-cell', true);

    shadesContainer.className = 'smart-shades';

  _renderColorLabels() {
    const that = this;
    const colorLabelsContainer = document.createElement('div');
    const colorLabelsArray = ['Red', 'Pink', 'Purple', 'Deep Purple', 'Indigo', 'Blue', 'Light Blue', 'Cyan', 'Teal', 'Green', 'Light Green', 'Lime', 'Yellow', 'Amber', 'Orange', 'Deep Orange', 'Brown', 'Grey', 'Blue Grey'];
    const colorLabelsColumn = that._renderRow(colorLabelsArray, 'smart-color-label', true);

    colorLabelsContainer.className = 'smart-color-labels';
    that._colorLabelsContainer = colorLabelsContainer;
  // Renders a single row of colors.
  _renderRow(array, cellClass, addInnerHtml) {
    const ul = document.createElement('ul');

    for (let index = 0, length = array.length; index < length; index++) {
      const currentElement = array[index];
      const li = document.createElement('li');

      if (addInnerHtml) {
        li.innerHTML = currentElement;
      else { = currentElement;
        li.setAttribute('data-color', currentElement);

      li.className = cellClass;


    return ul;
  // Fires a 'change' event when a color is selected.
  _addHandlers() {
    const that = this;

    const cells = that.querySelectorAll('.smart-color-cell');

    for(let i = 0; i < cells.length; i++) {
      const  cell = cells[i];

      cell.addEventListener('click', function() {
        that._currentColorHex ='data-color');
        that._currentColorRgb =;
        that.color = that.getColor().hex.toString();
  // gets the selected color.
  getColor() {
    const that = this;
    const rgb = that._currentColorRgb.match(/\d+/g);

    return {
      hex: that._currentColorHex.substring(1),
      r: parseInt(rgb[0]),
      g: parseInt(rgb[1]),
      b: parseInt(rgb[2])

See the Pen SMART HTML ELEMENTS by Boyko Markov (@boyko-markov) on CodePen.

HTML Elements, Javascript, Web Components

Leave a comment

TreeGrid and Grouping

Tree Grid, Grouping, Context Menus

The latest version of Smart HTML Elements brings important new features to our Smart Grid Web Component. It is now possible to display data hierarchies in the web component. The Grid allows you to display data as a combination of Tree and Grid. The Tree Grid mode has full support for data sorting, data filtering and data editing. The Grouping features allows you to group data by columns. The context menu feature allows you to quickly add a context menu functionality to the Grid.

Tree Grid

Tree Grid mode allows you to display hierarchical data in the Grid and make the component work like a hybrid between Tree and Grid.

grid custom element column template
Tree Grid

Virtual Tree Grid

In Virtual Mode, new rows are loaded on demand when you expand a row. This process repeats until the "leaf" property of the row is set to true.

Virtual Tree Grid

Virtual Tree Grid Pagination

With Pagination enabled, Root rows are loaded on demand when the current page is changed. Sub Rows are loaded when a treegrid row is expanded.

grid custom element column template

Virtual Tree Grid Pagination

Grid Grouping

Grouping enables you to group the component by one or multiple columns. The grouping styling is customizable through CSS Variables.

Grid GroupBy Grouping

Grid Grouping Grouping Styling

Grid Context Menu

Context Menu Grid Context Menu
HTML Elements, Javascript, Smart Grid
, , ,

Leave a comment

New Grid Features

Newest features in the Grid

HTML Elements, Smart Grid

Leave a comment

Lazy Initialization of Web Components

This post shows how to create a Grid Web component and initialize it from a DIV tag

The next version ver3.1.0 of Smart HTML Elements will introduce an alternative way to create a Web Component on demand from an existing HTML Element.

Let's look at the sample below. In the 'index.htm' web page code, we see a HTMLDIVElement(DIV tag) with id="grid". We will use that HTML element to create a new Grid Web Component instance.

<!DOCTYPE html>  
 <html xmlns="">  
   <title>Grid Lazy Load Demo</title>  
   <meta http-equiv="X-UA-Compatible" content="IE=edge" />  
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
   <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />  
   <link rel="stylesheet" type="text/css" href="../../../source/styles/smart.default.css" />  
   <link rel="stylesheet" type="text/css" href="../../../styles/demos.css" />  
   <link rel="stylesheet" type="text/css" href="../../../styles/common.css" />  
   <link rel="stylesheet" type="text/css" href="styles.css" />  
   <script type="text/javascript" src="../../../scripts/common.js"></script>  
   <script type="text/javascript" src=""></script>  
   <script type="module" src="index.js">  
   <div id="grid"></div>  

The 'index.js' file is defined as a Javascript Module. In that module our grid web component is created on window.onload, within a function called 'init()'. That is achieved by calling the Smart.Grid function and passing as a first argument the 'id' of the DIV tag and as a second argument the initialization object with the Grid web component's dataSource, columns and other configuration options. As a result, our DIV tag is replaced with a 'smart-grid' tag and a Grid is displayed.

That approach is useful, when we want to update an existing application with minimum changes or to create a Smart Web Component on demand with ES6 code.

import "../../../source/smart.elements.js";  
import "../../../scripts/data.js";  
document.readyState === 'complete' ? init() : window.onload = init;  
 function init() {  
   const grid = new Smart.Grid('#grid', {  
     dataSource: new Smart.DataAdapter(  
       dataSource: Data,  
         'id: number',  
         'firstName: string',  
         'lastName: string',  
         'productName: string',  
         'available: bool',  
         'quantity: number',  
         'price: number',  
         'total: number'  
     columns: [  
       label: 'First Name', dataField: 'firstName'  
     { label: 'Last Name', dataField: 'lastName' },  
     { label: 'Product', dataField: 'productName' },  
     { label: 'Available', dataField: 'available', template: 'checkBox', editor: 'checkBox' },  
     { label: 'Quantity', dataField: 'quantity', editor: 'numberInput' },  
     { label: 'Unit Price', dataField: 'price', editor: 'numberInput', cellsFormat: 'c2' }  
HTML Elements, Javascript, Web Components
, , ,

Leave a comment

Chart Custom Element Released

Best Chart Custom Element has just arrived

The latest version of Smart HTML Elements, brings a full featured Chart Custom Element with more than 30 different Data Visualization options. The Chart Types supported are listed: Chart Types.

Best Chart Custom Element

Our Chart Custom Element is written in JavaScript and CSS. It does not depend on any other third-party scripts. The rendering is achieved with SVG and HTML5 canvas. The Chart works well on mobile browsers and is the most feature-complete chart available in the web components world.
Data displayed on the Chart can be formatted in multiple different ways. For example, the charting element has a property called 'formatSettings' with the following data formatting options.

  • decimalSeparator - character used as a decimal separator. If not specified, the default separator is '.'
  • thousandsSeparator - character used as thousands separator. Default value is ','
  • decimalPlaces - number of digits after the decimal separator. Default value is 2 for floating point numbers.
  • negativeWithBrackets - boolean which specifies whether to display negative numbers in brackets. Default value is false.
  • prefix - any string which will be added as a prefix. Default value is empty.
  • sufix - any string which will be added as a sufix. Default value is empty.
  • dateFormat - optional date format string. This property is applicable only when displaying Date objects.

The image below illustrates the Axes supported by the custom element. Smart.Chart has two main types of axes - valueAxis and xAxis. Typically the valueAxis represents the vertical axis in the chart although you may choose to rotate the axes and in this case the valueAxis will be displayed horizontally.Chart Custom Element Axes

Smart.Chart also ships with 32 built-in color schemes which are used to automatically set colors for different series. You can change the color scheme by setting the colorScheme property of the chart. The available value are from 'scheme01' to 'scheme32'. By setting its 'theme' property, users can Data Visualize their graphics in 'Light' and 'Dark' mode. Smart.Chart is based on: jqxChart.

We invite you to look at our Chart Custom Element demos: Chart overview
HTML Elements, Javascript, Web Components

Leave a comment

Binding to Row, Cell and Column Events in Grid Web Component

This post shows how to bind to the Grid Web Component events. The code below initializes the Grid instance and binds to the 'click' event. Within the event handler, we can get details about which part of the Grid was clicked - Cell, Row or Column. This is achieved by utilizing the 'event.path' array. It is also important to note that each Data Grid Column has 'data-field' attribute and each Row has 'data-id' attribute. The data source, which is used in the example is available in the 'data.js' file from the download package.

 Smart('#grid', class {  
      get properties() {  
           return {  
                dataSource: new Smart.DataAdapter(  
                     dataSource: getCountriesData(),  
                          'ID: number',  
                          'Country: string',  
                          'Area: number',  
                          'Population_Urban: number',  
                          'Population_Rural: number',  
                          'Population_Total: number',  
                          'GDP_Agriculture: number',  
                          'GDP_Industry: number',  
                          'GDP_Services: number',  
                          'GDP_Total: number'  
                columns: [  
 window.onload = function() {  
  grid.addEventListener('click', function(event){  
     const path = event.path;  
     let cell = null;  
     let row = null;  
     let column = null;  
     for(let i = 0; i < path.length; i++) {  
       const node = path[i];  
       if (node.nodeName === 'SMART-GRID-CELL') {  
         cell = node;  
       if (node.nodeName === 'SMART-GRID-ROW') {  
         row = node;  
       if (node.nodeName === 'SMART-GRID-COLUMN')      {  
         column = node;  
     if (row) {  
     if (column) {  
     if (cell) {  
Smart Grid, Web Components

Leave a comment

AutoComplete Input Custom Element also known as Typeahead

The newest version of our framework marks the availability of a new AutoComplete Input tag. We needed such lightweight component for the purposes of our Grid web component.
There, it is used as an inline cell editor. You can check it out here: grid-editing-cell-auto-complete.

Here is how the web component looks like when you add it to your web page:

Auto Complete Input

All you need to do is to add a reference to smart.elements.js, smart.default.css and type the following:

 <smart-input data-source="[South America, North America, Asia, Africa, Europe]"></smart-input>  
, , , , , , , , , ,

Leave a comment