Use Bootstrap with ZK: Responsive Admin Template"

From Documentation
 
(2 intermediate revisions by the same user not shown)
Line 13: Line 13:
 
* create a custom component with shadow components
 
* create a custom component with shadow components
 
* develop in MVVM pattern
 
* develop in MVVM pattern
 +
 +
=Online Demo =
 +
[https://www.zkoss.org/admin-template/  Admin Template Demo]
  
 
= Designers Involved =
 
= Designers Involved =
Line 32: Line 35:
  
  
By <tt><apply></tt>, we can simplify the home page to few lines:
+
By <code><apply></code>, we can simplify the home page to few lines:
  
 
'''index.zul'''
 
'''index.zul'''
<source lang='xml' high='4'>
+
<source lang='xml' highlight='4'>
 
     <hlayout viewModel="@id('vm')@init('org.zkoss.admin.MainVM')" width="100%">
 
     <hlayout viewModel="@id('vm')@init('org.zkoss.admin.MainVM')" width="100%">
 
         <apply templateURI="sidebar.zul" />
 
         <apply templateURI="sidebar.zul" />
Line 45: Line 48:
  
  
For switching among pages, I create <tt>NavigationModel</tt> and store it as a desktop attribute. Then, keep track the current zul at <tt>NavigationModel.contentUrl</tt> and bind this property to  <tt>templateURI</tt> of <tt><apply></tt>. When a user clicks an item on the sidebar, we just set zul file path at <tt>NavigationModel.contentUrl</tt>, so that <tt><apply></tt> will load the corresponding zul.
+
For switching among pages, I create <code>NavigationModel</code> and store it as a desktop attribute. Then, keep track the current zul at <code>NavigationModel.contentUrl</code> and bind this property to  <code>templateURI</code> of <code><apply></code>. When a user clicks an item on the sidebar, we just set zul file path at <code>NavigationModel.contentUrl</code>, so that <code><apply></code> will load the corresponding zul.
  
 
[[File:navigationModel.png | center]]
 
[[File:navigationModel.png | center]]
Line 63: Line 66:
  
 
Therefore, the page skeleton in a zul is:
 
Therefore, the page skeleton in a zul is:
<source lang='xml' high='1, 8,9'>
+
<source lang='xml' highlight='1, 8,9'>
 
<zk xmlns:n="native" >
 
<zk xmlns:n="native" >
 
     <div sclass="row">
 
     <div sclass="row">
Line 82: Line 85:
 
</zk>
 
</zk>
 
</source>
 
</source>
* line 1: declare [https://www.zkoss.org/wiki/ZUML_Reference/ZUML/Namespaces/Native namespace] so that we can use HTML <tt><div/></tt> to reduce memory consumption.
+
* line 1: declare [https://www.zkoss.org/wiki/ZUML_Reference/ZUML/Namespaces/Native namespace] so that we can use HTML <code><div/></code> to reduce memory consumption.
* line 8-9: specify <tt>col-md-7</tt> and <tt>col-md-5</tt> to define a column width.
+
* line 8-9: specify <code>col-md-7</code> and <code>col-md-5</code> to define a column width.
  
 
== Padding & Margin ==
 
== Padding & Margin ==
To apply padding and margin, we strongly suggest using Bootstrap's [https://getbootstrap.com/docs/4.3/utilities/spacing/ space utility CSS class]. The classes are named using the format <span style="color: deeppink"><tt>{property}{sides}-{size}</tt></span>. Bootstrap provides 5 levels of size (p-1 to p-5), and each is proportional to '''$spacers'''.  
+
To apply padding and margin, we strongly suggest using Bootstrap's [https://getbootstrap.com/docs/4.3/utilities/spacing/ space utility CSS class]. The classes are named using the format <span style="color: deeppink"><code>{property}{sides}-{size}</code></span>. Bootstrap provides 5 levels of size (p-1 to p-5), and each is proportional to '''$spacers'''.  
  
 
Hence, we can easily specify '''p-1''' to apply '''5px''' padding for each column (or '''p-2''' to apply '''10px'''). No need to specify pixels in CSS. These space utility can greatly simplify the troublesome tasks of specifying pixels.
 
Hence, we can easily specify '''p-1''' to apply '''5px''' padding for each column (or '''p-2''' to apply '''10px'''). No need to specify pixels in CSS. These space utility can greatly simplify the troublesome tasks of specifying pixels.
  
<source lang='xml' high='1,2'>
+
<source lang='xml' highlight='1,2'>
 
     <div sclass="row py-1">
 
     <div sclass="row py-1">
 
         <n:div sclass="col-md-7 p-1">
 
         <n:div sclass="col-md-7 p-1">
Line 110: Line 113:
  
 
=== Declare a Custom Component ===
 
=== Declare a Custom Component ===
Since a div with <tt>row</tt> class is commonly used in every zul, to avoid typing duplicate code in zul, we create a custom component, <tt>bs-row</tt>, with the pre-defined sclass, so that we don't have to specify each div.
+
Since a div with <code>row</code> class is commonly used in every zul, to avoid typing duplicate code in zul, we create a custom component, <code>bs-row</code>, with the pre-defined sclass, so that we don't have to specify each div.
  
 
<source lang='xml'>
 
<source lang='xml'>
Line 148: Line 151:
 
[[File:separate-zul.png | center]]
 
[[File:separate-zul.png | center]]
  
Shadow component <tt><apply/></tt> can easily help us do it:
+
Shadow component <code><apply/></code> can easily help us do it:
  
<source lang='xml' high='3, 7, 10'>
+
<source lang='xml' highlight='3, 7, 10'>
 
...
 
...
 
     <bs-row>
 
     <bs-row>
Line 172: Line 175:
 
[[File:nested-row.png | center]]
 
[[File:nested-row.png | center]]
  
<source lang='xml' high='6, 17'>
+
<source lang='xml' highlight='6, 17'>
 
         <bs-row>
 
         <bs-row>
 
             <n:div class="col-lg-1">
 
             <n:div class="col-lg-1">
Line 199: Line 202:
 
         </bs-row>
 
         </bs-row>
 
</source>
 
</source>
* line 6: To make a component fill up a column and resize itself with a column width, we should use <tt>hflex="1"</tt>
+
* line 6: To make a component fill up a column and resize itself with a column width, we should use <code>hflex="1"</code>
 
* line 17: align text with [https://getbootstrap.com/docs/4.3/utilities/text/ Bootstrap utility class]
 
* line 17: align text with [https://getbootstrap.com/docs/4.3/utilities/text/ Bootstrap utility class]
  
Line 215: Line 218:
  
 
==Switching Sidebar ==
 
==Switching Sidebar ==
We implement this responsive sidebar by toggle <tt>collapsed</tt> attribute.
+
We implement this responsive sidebar by toggle <code>collapsed</code> attribute.
  
First, we declare a boolean for <tt>collapsed</tt> attribute and detect browser width with <tt>@MatchMedia</tt>. When the browser width is wider than 958px, we set it to false, otherwise we set it to true.
+
First, we declare a boolean for <code>collapsed</code> attribute and detect browser width with <code>@MatchMedia</code>. When the browser width is wider than 958px, we set it to false, otherwise we set it to true.
<source lang='java' high='8, 11'>
+
<source lang='java' highlight='8, 11'>
 
public class SidebarVM {
 
public class SidebarVM {
 
     ...
 
     ...
Line 241: Line 244:
 
</source>
 
</source>
  
Then, bind <tt>collapsed</tt> with the boolean property <tt>vm.collapsed</tt>.
+
Then, bind <code>collapsed</code> with the boolean property <code>vm.collapsed</code>.
 
<source lang='xml'>
 
<source lang='xml'>
 
<navbar orient="vertical" collapsed="@load(vm.collapsed)">
 
<navbar orient="vertical" collapsed="@load(vm.collapsed)">
 
</source>
 
</source>
  
We can also control the badge text's visibility by <tt>vm.collapsed</tt>:
+
We can also control the badge text's visibility by <code>vm.collapsed</code>:
<source lang='xml' lang='xml' high='2'>
+
<source lang='xml' lang='xml' highlight='2'>
 
         <nav label="@load(menuItem.label)" iconSclass="@load(menuItem.icon)"
 
         <nav label="@load(menuItem.label)" iconSclass="@load(menuItem.icon)"
 
             badgeText="@load(vm.collapsed ? '': menuItem.counter)">
 
             badgeText="@load(vm.collapsed ? '': menuItem.counter)">
Line 262: Line 265:
 
ZK allows you to mix HTML tags in a zul by declaring a [https://www.zkoss.org/wiki/ZUML_Reference/ZUML/Namespaces/Native namespace]. For example, there are 2 namespaces in the zul below:
 
ZK allows you to mix HTML tags in a zul by declaring a [https://www.zkoss.org/wiki/ZUML_Reference/ZUML/Namespaces/Native namespace]. For example, there are 2 namespaces in the zul below:
 
   
 
   
<source lang='xml' high='1,2,6'>
+
<source lang='xml' highlight='1,2,6'>
 
<zk xmlns="native" xmlns:z="zul">
 
<zk xmlns="native" xmlns:z="zul">
 
<div class="state-box rounded p-1 ${color}">
 
<div class="state-box rounded p-1 ${color}">
Line 273: Line 276:
 
</source>
 
</source>
 
* Line 1: Since HTML tags are in a majority, we declare it as the default namespace to avoid all prefix on HTML tags.
 
* Line 1: Since HTML tags are in a majority, we declare it as the default namespace to avoid all prefix on HTML tags.
* Line 2: This div is an HTML div not a zk div. Therefore,  you can see we specify <tt>class</tt> instead of <tt>sclass</tt>.
+
* Line 2: This div is an HTML div not a zk div. Therefore,  you can see we specify <code>class</code> instead of <code>sclass</code>.
* Line 6: We declare namespace '''zul''' with the prefix '''z''', so this is a ZK <tt>Label</tt> component.
+
* Line 6: We declare namespace '''zul''' with the prefix '''z''', so this is a ZK <code>Label</code> component.
  
 
== state-box ==
 
== state-box ==
Line 285: Line 288:
  
 
[https://github.com/zkoss-demo/admin-template/blob/master/src/main/webapp/WEB-INF/template/stateBox.zul stateBox.zul]
 
[https://github.com/zkoss-demo/admin-template/blob/master/src/main/webapp/WEB-INF/template/stateBox.zul stateBox.zul]
<source lang='xml' high='3, 4, 9'>
+
<source lang='xml' highlight='3, 4, 9'>
 
<zk xmlns="native" xmlns:z="zul">
 
<zk xmlns="native" xmlns:z="zul">
 
     <div class="state-box rounded p-1">
 
     <div class="state-box rounded p-1">
Line 318: Line 321:
  
 
=== Use state-box ===
 
=== Use state-box ===
After declaring in a system-scope language definition, we can use the custom component <tt>state-box</tt> in any zul like:
+
After declaring in a system-scope language definition, we can use the custom component <code>state-box</code> in any zul like:
  
<source lang='xml' high='4'>
+
<source lang='xml' highlight='4'>
 
     <nodom viewModel="@id('vm')@init('org.zkoss.admin.ecommerce.StateVM')">
 
     <nodom viewModel="@id('vm')@init('org.zkoss.admin.ecommerce.StateVM')">
 
         <forEach items="@init(vm.states)">
 
         <forEach items="@init(vm.states)">
Line 330: Line 333:
 
</source>
 
</source>
 
* Line 1: [https://www.zkoss.org/wiki/ZK_Component_Reference/Containers/Nodom nodom] is a better component than div for just grouping components, since it doesn't generate any DOM element to a browser.
 
* Line 1: [https://www.zkoss.org/wiki/ZK_Component_Reference/Containers/Nodom nodom] is a better component than div for just grouping components, since it doesn't generate any DOM element to a browser.
* Line 3: Since we have 4 states to show, we specify <tt>col-lg-3</tt> for each state-box.
+
* Line 3: Since we have 4 states to show, we specify <code>col-lg-3</code> for each state-box.
  
<tt><state-box/></tt> is equivalent to :
+
<code><state-box/></code> is equivalent to :
 
<source lang='xml'>
 
<source lang='xml'>
 
<apply templateURI="for/WEB-INF/template/stateBox.zul"/>
 
<apply templateURI="for/WEB-INF/template/stateBox.zul"/>
Line 343: Line 346:
 
<source lang='xml'>
 
<source lang='xml'>
 
<state-box state="@init(each)"
 
<state-box state="@init(each)"
     icon="@init(each.type)@converter('org.zkoss.admin.converter.  
+
     icon="@init(each.type)@converter('org.zkoss.admin.converter.TypeIconConverter')"
 
     color="@init(each.type)@converter('org.zkoss.admin.converter.TypeColorConverter')"/>
 
     color="@init(each.type)@converter('org.zkoss.admin.converter.TypeColorConverter')"/>
 
</source>
 
</source>
* Line 1: <tt>state</tt> is the key and it is also the variable name you reference with EL/data binding expression. <tt>@init(each)</tt> is the data object.
+
* Line 1: <code>state</code> is the key and it is also the variable name you reference with EL/data binding expression. <code>@init(each)</code> is the data object.
  
Inside a <tt>state-box</tt>, we can render data with EL or data binding.
+
Inside a <code>state-box</code>, we can render data with EL or data binding.
<source lang='xml' high='1, 4,5,6,10'>
+
<source lang='xml' highlight='1, 4,5,6,10'>
 
     <div class="state-box rounded p-1 ${color}">
 
     <div class="state-box rounded p-1 ${color}">
 
         <div class="row">
 
         <div class="row">
Line 368: Line 371:
  
  
We implement <tt><info-box/></tt> in a similar way.
+
We implement <code><info-box/></code> in a similar way.
  
 
= Download & Online Demo=
 
= Download & Online Demo=

Latest revision as of 12:05, 21 July 2023

DocumentationSmall Talks2019AugustUse Bootstrap with ZK: Responsive Admin Template
Use Bootstrap with ZK: Responsive Admin Template

Author
Hawk Chen, Engineer, Potix Corporation
Date
August, 2019
Version
ZK 8.6.2

Overview

Bootstrap is a good friend to ZK framework. It provides a Grid system to apply responsive design on the page level and lots of utility CSS classes for setting color, alignment, padding, margin, and size. These utility are easy to pick up and apply within a zul file. In this small talk we have created an admin template application leveraging Bootstrap features to demonstrate various usages including:

  • build an administration UI with ZK components
  • reusing view snippet as a template
  • easily apply responsive design (RWD) with Bootstrap
  • create a custom component with shadow components
  • develop in MVVM pattern

Online Demo

Admin Template Demo

Designers Involved

Responsive web design (RWD) doesn't just happen magically, and it's also not a pure technical problem. At component level, ZK EE components can help -- they will turn themselves into different look & feel that best match the device they are on. But at page level, you cannot just make everything smaller, you need to decide what you wish to display in a smaller/limited screen. And to further make the page look nice it involves many things such as: the layout, colors, font size, padding, and margin.

Ideally the process starts with a designer that designs the pages for different responsive sizes. Then you, as a developer, implement these pages according to the design with tools like ZK and bootstrap. Here, with the right tools you can implement these pages much easier. In the case that there is no designer working with you, you can just reference a commonly-seen layout to get started.

In our case, we are lucky enough to have a designer who created the layout and styles for us.

Admin-template-design.png

Navigation

We start from navigation. As you can see, it is a typical layout for an administration system: sidebar + content

The sidebar shows the navigation items, and it determines the content. When a user click an item in the sidebar, it loads the corresponding content zul (e.g. ecommerce.zul or project.zul)

Admin-layout.png


By <apply>, we can simplify the home page to few lines:

index.zul

    <hlayout viewModel="@id('vm')@init('org.zkoss.admin.MainVM')" width="100%">
        <apply templateURI="sidebar.zul" />
        <div sclass="container-fluid" hflex="1">
            <apply templateURI="@load(vm.navigationModel.contentUrl)"/>
        </div>
    </hlayout>


For switching among pages, I create NavigationModel and store it as a desktop attribute. Then, keep track the current zul at NavigationModel.contentUrl and bind this property to templateURI of <apply>. When a user clicks an item on the sidebar, we just set zul file path at NavigationModel.contentUrl, so that <apply> will load the corresponding zul.

NavigationModel.png

Responsive Design Layout (RWD) with Bootstrap

Bootstrap's grid system provides a great approach to achieve responsive design by dividing a page into rows. Each row is divided into 12 columns. We can specify the number of columns for each block in each row, for example:

  1. divide the content block into 5 rows
  2. divide the 3rd rows into 2 blocks: 7 columns and 5 columns
Row-col.png

The result looks like:

Row-col-page.png


Therefore, the page skeleton in a zul is:

<zk xmlns:n="native" >
    <div sclass="row">
        <n:div sclass="col"></n:div>
    </div>
    <div sclass="row">
    </div>
    <div sclass="row">
        <n:div sclass="col-md-7"></n:div>
        <n:div sclass="col-md-5"></n:div>
    <div sclass="row">
        <n:div sclass="col-md-5"></n:div>
        <n:div sclass="col-md-7"></n:div>
    </div>
    <div sclass="row">
        <n:div class="col-md-12"></n:div>
    </div>
</zk>
  • line 1: declare namespace so that we can use HTML
    to reduce memory consumption.
  • line 8-9: specify col-md-7 and col-md-5 to define a column width.

Padding & Margin

To apply padding and margin, we strongly suggest using Bootstrap's space utility CSS class. The classes are named using the format {property}{sides}-{size}. Bootstrap provides 5 levels of size (p-1 to p-5), and each is proportional to $spacers.

Hence, we can easily specify p-1 to apply 5px padding for each column (or p-2 to apply 10px). No need to specify pixels in CSS. These space utility can greatly simplify the troublesome tasks of specifying pixels.

    <div sclass="row py-1">
        <n:div sclass="col-md-7 p-1">
            ...
        </n:div>
        <n:div sclass="col-md-5 p-1">
            ...
        </n:div>
    </div>
  • line2: To add space among rows, we specify py-1 on each row, which gives it 10px for top and bottom padding. (y for y-axis)

Reusing ZUL Snippet

In ecommerce.zul, you can see duplicate code below in several places:

    <div sclass="row py-1">
    </div>

Declare a Custom Component

Since a div with row class is commonly used in every zul, to avoid typing duplicate code in zul, we create a custom component, bs-row, with the pre-defined sclass, so that we don't have to specify each div.

	<component>
		<component-name>bs-row</component-name>
		<extends>div</extends>
		<property>
			<property-name>sclass</property-name>
			<property-value>row py-1</property-value>
		</property>
	</component>
<zk xmlns:n="native">
    <bs-row>
        ...
    </bs-row>
    <bs-row>
        ...
    </bs-row>
    <bs-row>
        ...
    </bs-row>
    <bs-row>
        ...
    </bs-row>
    <bs-row>
        ...
    </bs-row>
</zk>

Divide a Page

For such a big page, we strongly recommend you to divide it into several smaller zul files to reduce the complexity and increase the modularity. Each zul file has its own controller and doesn't depends on others, so that it is easier to rearrange them in future, e.g. you might want to switch positions of marketShare.zul and sales.zul.

Separate-zul.png

Shadow component <apply/> can easily help us do it:

...
    <bs-row>
        <apply templateURI="ecommerce/stateBoard.zul"/>
    </bs-row>
    <bs-row >
        <n:div sclass="col-md-7 p-1">
            <apply templateURI="ecommerce/revenueReport.zul"/>
        </n:div>
        <n:div sclass="col-md-5 p-1">
            <apply templateURI="ecommerce/sales.zul"/>
        </n:div>
    </bs-row>
...

line 3: ZK injects the components in stateBoard.zul at this line, just like pasting the content of stateBoard.zul manually.

Nested Rows

Even in a single column, bootstrap row can also help you layout components. In revenuReport.zul, we can divide it into 2 rows and separate each components into columns:

Nested-row.png
        <bs-row>
            <n:div class="col-lg-1">
                From
            </n:div>
            <n:div class="col-lg-2">
                <datebox hflex="1"/>
            </n:div>
            <n:div class="col-lg-1">
                To
            </n:div>
            <n:div class="col-lg-2">
                <datebox hflex="1"/>
            </n:div>
            <n:div class="col-lg-1">
                <button label="Apply"/>
            </n:div>
            <n:div class="col-lg-5 text-right">
                <button label="View Statements" />
            </n:div>
        </bs-row>
        <bs-row>
            <n:div class="col-12">
                <charts id="chart" type="areaspline" title="" hflex="1"/>
            </n:div>
        </bs-row>
  • line 6: To make a component fill up a column and resize itself with a column width, we should use hflex="1"
  • line 17: align text with Bootstrap utility class

Responsive Design (RWD) with ZK

Bootstrap's grid system can make rows responsive, but to change ZK component's style for responsiveness you can use @MatchMedia.

In admin template project, the sidebar is responsive to browser width:

wider sidebar

Wide.png

narrow sidebar

Narrow.png


Switching Sidebar

We implement this responsive sidebar by toggle collapsed attribute.

First, we declare a boolean for collapsed attribute and detect browser width with @MatchMedia. When the browser width is wider than 958px, we set it to false, otherwise we set it to true.

public class SidebarVM {
    ...
    private boolean collapsed = false; //sidebar is collapsed for narrow screen

    ...

    // medium breakpoint 768 + 190 (sidebar width)
    @MatchMedia("all and (min-width: 958px)")
    @NotifyChange("collapsed")
    public void beWide(){
        collapsed = false;
    }

    @MatchMedia("all and (max-width: 957px)")
    @NotifyChange("collapsed")
    public void beNarrow(){
        collapsed = true;
    }
...
}

Then, bind collapsed with the boolean property vm.collapsed.

<navbar orient="vertical" collapsed="@load(vm.collapsed)">

We can also control the badge text's visibility by vm.collapsed:

        <nav label="@load(menuItem.label)" iconSclass="@load(menuItem.icon)"
             badgeText="@load(vm.collapsed ? '': menuItem.counter)">
            ...
        </nav>

Create Your Custom Component

With the help of shadow components and namespace, we can easily create custom components. Hence, you can design your own component in HTML and use it in a zul. In this section, I will introduce how to implement it using state box as an example:

Statebox.png

Use HTML Elements with Namespace

ZK allows you to mix HTML tags in a zul by declaring a namespace. For example, there are 2 namespaces in the zul below:

<zk xmlns="native" xmlns:z="zul">
<div class="state-box rounded p-1 ${color}">
...
    <h6 class="text-black-50">${state.type}</h6>
    <h4>${state.value}</h4>
    <z:label sclass="text-success" .../>
...
</div>
  • Line 1: Since HTML tags are in a majority, we declare it as the default namespace to avoid all prefix on HTML tags.
  • Line 2: This div is an HTML div not a zk div. Therefore, you can see we specify class instead of sclass.
  • Line 6: We declare namespace zul with the prefix z, so this is a ZK Label component.

state-box

Implement Layout

We still can divide a state-box with a row and 2 columns:

In-statebox.png

Then we compose this box mainly with HTML tags:

stateBox.zul

<zk xmlns="native" xmlns:z="zul">
    <div class="state-box rounded p-1">
        <div class="row">
            <div class="col-8 px-4">
                <h6 class="text-black-50"></h6>
                <h4></h4>
                <z:label sclass="text-success" />
            </div>
            <div class="col-4 text-right px-4">
                <h2>
                <i class=" text-black-50 h3"/>
                </h2>
            </div>
        </div>
    </div>
</zk>

Declare as a Custom Component

We put the code snippet above into an independent zul file and declare it as a custom component In metainfo/zk/lang-addon.xml:

	<component>
		<component-name>state-box</component-name>
		<template-uri>/WEB-INF/template/stateBox.zul</template-uri>
	</component>
	<stylesheet href="/resources/css/state-box.css" type="text/css"/>


Use state-box

After declaring in a system-scope language definition, we can use the custom component state-box in any zul like:

    <nodom viewModel="@id('vm')@init('org.zkoss.admin.ecommerce.StateVM')">
        <forEach items="@init(vm.states)">
            <n:div sclass="col-12 col-md-6 col-lg-3 p-1">
                <state-box />
            </n:div>
        </forEach>
    </nodom>
  • Line 1: nodom is a better component than div for just grouping components, since it doesn't generate any DOM element to a browser.
  • Line 3: Since we have 4 states to show, we specify col-lg-3 for each state-box.

<state-box/> is equivalent to :

<apply templateURI="for/WEB-INF/template/stateBox.zul"/>


Pass Data Into state-box

We can pass data into state-box as parameters, so this can make a state-box more modularize and reusable:

<state-box state="@init(each)"
    icon="@init(each.type)@converter('org.zkoss.admin.converter.TypeIconConverter')"
    color="@init(each.type)@converter('org.zkoss.admin.converter.TypeColorConverter')"/>
  • Line 1: state is the key and it is also the variable name you reference with EL/data binding expression. @init(each) is the data object.

Inside a state-box, we can render data with EL or data binding.

    <div class="state-box rounded p-1 ${color}">
        <div class="row">
            <div class="col-8 px-4">
                <h6 class="text-black-50">${state.type}</h6>
                <h4>${state.value}</h4>
                <z:label sclass="text-success" value="@init(state.ratio)@converter('org.zkoss.admin.converter.PercentageConverter')"/>
            </div>
            <div class="col-4 text-right px-4">
                <h2>
                <i class="${icon} text-black-50 h3"/>
                </h2>
            </div>
        </div>
    </div>
  • Line 6: Since HTML tag doesn't support data binding, we need to bind the server's data and a converter to a ZK Label.


We implement <info-box/> in a similar way.

Download & Online Demo

I hope you enjoyed reading this article, and have learned how you can use ZK with Bootstrap's Grid and Utility CSS Classes to create responsive and impressive Web applications. You can download the project from:

Other Responsive Design Tips

The following articles introduce more tips about responsive design:


Comments



Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.