Skip to content

Thymeleaf dialect to create interface components bootstrap like

License

Notifications You must be signed in to change notification settings

jpenren/thymeleaf-ui-dialect

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

60 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Thymeleaf UI Dialect

Thymeleaf dialect to create interface components, provides a simple way to define reusable components and some html attributes to render user interface (html) components.

See demo project: https://github.com/jpenren/thymeleaf-ui-dialect-demo

Usage

Add the Maven dependency to your project:

<dependency>
	<groupId>io.github.jpenren</groupId>
	<artifactId>thymeleaf-ui-dialect</artifactId>
	<version>1.1.0</version>
</dependency>

This library uses Spring Boot autoconfiguration feature, if required you can define this dialect manually:

templateEngine.addDialect(new UiDialect());
String theme = "default";
templateEngine.addTemplateResolver(new ComponentTemplateResolver(theme));

Components

Enabling this dialect will introduce the ui namespace and a new set of attribute processors for available components:

Alert

Template:

<div ui:alert="#{msg.key}" ui:dismissible="true"></div>

Output:

<div class="alert alert-primary alert-dismissible fade show" role="alert">
  Alert message
  <button type="button" class="close" data-dismiss="alert" aria-label="Close">
    <span aria-hidden="true">&times;</span>
  </button>
</div>

Badge

Template:

<span ui:badge="value"></span>

Output:

<span class="badge badge-secondary">value</span>

Template:

<span ui:badge="value" ui:href="'http://www.example.org'"></span>

Output:

<a class="badge badge-secondary" href="http://www.example.org">value</a>

Breadcrumb

Template:

<div ui:breadcrumb ui:locations="${ {#ui.location('http://url','Home'), #ui.location('Current page')} }"></div>

Output:

<nav aria-label="breadcrumb">
  <ol class="breadcrumb">
    <li class="breadcrumb-item">
      <a href="http://url">Home</a>
    </li>
    <li class="breadcrumb-item active" aria-current="page">
      Current page
    </li>
  </ol>
</nav>

Button

Template:

<button ui:button ui:toggle="true" ui:active="true"></button>

Output:

<button type="button" class="btn btn-primary active" data-toggle="button"></button>

Card

Template:

<div ui:card ui:header="Header" ui:image="${#ui.image('http://url','alt text','title')}" ui:footer="Footer"></div>

Output:

<div class="card">
    <div class="card-header">Header</div>
    <img class="card-img-top" src="http://url" alt="alt text">
    <div class="card-body">
    </div>
    <div class="card-footer text-muted">Footer</div>
</div>

Carousel

Template:

<div ui:carousel ui:slides="${ {#ui.slide('#{http://url}','Caption'), #ui.slide('http://url')} }" ui:show-controls="true" ui:show-indicators="true"></div>

Output:

<div class="carousel slide" data-ride="carousel" id="car_1551028552310">
  <ol class="carousel-indicators">
    <li data-slide-to="0" data-target="#car_1551028552310" class="active"></li>
    <li data-slide-to="1" data-target="#car_1551028552310"></li>
  </ol>
  <div class="carousel-inner">
    <div class="carousel-item active">
      <img class="d-block w-100" src="#{http://url}">
      <div class="carousel-caption d-none d-md-block">??Caption_es_ES??</div>
    </div>
    <div class="carousel-item">
      <img class="d-block w-100" src="http://url">
    </div>
  </div>
  <a class="carousel-control-prev" href="#car_1551028552310" role="button" data-slide="prev">
    <span class="carousel-control-prev-icon" aria-hidden="true"></span>
    <span class="sr-only">Previous</span>
  </a>
  <a class="carousel-control-next" href="#car_1551028552310" role="button" data-slide="next">
    <span class="carousel-control-next-icon" aria-hidden="true"></span>
    <span class="sr-only">Next</span>
  </a>
</div>

Dropdown

Template:

<div ui:dropdown="#{toggle}" ui:header="#{header}" ui:items="${ {#ui.link('href', 'text'), #ui.divider, #ui.link('rerf','tex')} }"></div>

Output:

<div class="dropdown">
  <button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Toggle</button>
  <div class="dropdown-menu">
        <h6 class="dropdown-header">Header</h6>
        <a class="dropdown-item" href="href">Text</a>
        <div class="dropdown-divider"></div>
        <a class="dropdown-item" href="rerf">Text</a>
  </div>
</div>

Figure

Template:

<div ui:figure="${#ui.image('http://url')}" ui:caption="#{caption}"></div>

Output:

<figure class="figure">
    <img src="http://url" class="figure-img img-fluid">
    <figcaption class="figure-caption">Caption text</figcaption>
</figure>

Navigation

Template:

<div ui:nav ui:items="${ {#ui.link('href', 'text'),#ui.link('href','text')} }"></div>

Output:

<ul class="nav">
    <li class="nav-item" >
      <a class="nav-link" href="href">Text</a>
    </li>
    <li class="nav-item" >
      <a class="nav-link" href="href">Text</a>
    </li>
</ul>

Navigation header

Template:

<nav ui:nav-header ui:brand="${ #ui.link('href','text') }" ui:items="${ {#ui.link('ref','alt')} }"></nav>

Output:

<nav class="navbar navbar-light bg-light">
  <a class="navbar-brand" href="href">Text</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarSupportedContent">
    <ul class="navbar-nav mr-auto">
      <li class="nav-item">
        <a class="nav-link" href="href">Text</a>
      </li>
    </ul>
  </div>
</nav>

Example with Java code:

import static io.github.thymeleaf.ui.Components.*;
...
@ControllerAdvice
public class UiControllerAdvice {
    
    @ModelAttribute
    public NavigationHeader addNavigationHeader() {
        NavigationHeader header = navigationHeader("#", "navheader", link("#", "text"));
        Dropdown dropdown = dropdown("toggle", "t1");
        dropdown.add(link("#", "text"));
        dropdown.add(link("#", "text"));
        dropdown.divider();
        dropdown.add(link("#", "text"));
        header.add(dropdown);
        
        return header;
    }
}

Template:

<nav ui:nav-header></nav>

Output:

<nav class="navbar navbar-light bg-light">
  <a class="navbar-brand" href="href">Text</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarSupportedContent">
    <ul class="navbar-nav mr-auto">
      <li class="nav-item">
        <a class="nav-link" href="#">Text</a>
      </li>
      <li class="nav-item dropdown">
        <a class="nav-link dropdown-toggle" id="t1" aria-expanded="false" href="#" role="button" data-toggle="dropdown" aria-haspopup="true">Toogle</a>
        <div class="dropdown-menu" aria-labelledby="t1">
          <a href="#" class="dropdown-item">Text</a>
          <a href="#" class="dropdown-item">Text</a>
          <div class="dropdown-divider"></div>
          <a href="#" class="dropdown-item">Text</a>
        </div>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="href">Text</a>
      </li>
    </ul>
  </div>
</nav>

Sidebar

Template:

<nav ui:sidebar="mySidebar" ui:header="#{header}" ui:items="${ {#ui.link('href','text'), #ui.link('href','text')} }"></nav>

Output:

<nav class="sidebar-nav">
  <div class="sidebar-header">Header</div>
  <ul>
    <li>
      <a href="href">Text</a>
    </li>
    <li>
      <a href="href">Text</a>
    </li>
  </ul>
</nav>

Exmple with Java code:

import static io.github.thymeleaf.ui.Components.*;
...
@ControllerAdvice
public class UiControllerAdvice {

    @ModelAttribute
    public Sidebar addSidebar() {
        Sidebar sidebar = sidebar("Header", link("#", "text"), link("#", "text"));
        sidebar.add(submenu("Menu", link("#", "text"), link("#", "text")));
            
        return sidebar;
    }
}

Template

<nav ui:sidebar></nav>

Output:

<nav class="sidebar-nav">
  <div class="sidebar-header">Header</div>
  <ul>
    <li>
      <a href="#">text</a>
    </li>
    <li>
      <a href="#">text</a>
    </li>
    <li>
      <a href="#menu_1551030034192" data-toggle="collapse" class="dropdown-toggle" aria-expanded="false">Menu</a>
      <ul id="menu_1551030034192" class="sidebar-nav-menu collapse">
        <li>
          <a href="#">text</a>
        </li>
        <li>
          <a href="#">text</a>
        </li>
      </ul>
    </li>
  </ul>
</nav>

Create UI components in Java

Spring MVC @Controller:

import static io.github.thymeleaf.ui.Components.*;
...

@GetMapping("/index")
public String index(ModelMap model){
	
    // Alert
    model.addAttribute("alert", alert("This is an alert"));	
    
    //Badge
    model.addAttribute("badge", badge("4"));
    model.addAttribute("badge2", badge("5"));
    
    //Breadcrumb
    Breadcrumb breadcrumb = breadcrumb(location("/", "home"), location("/", "admin"), location("current-page"));
    model.addAttribute(breadcrumb);
    
    //Card
    Card card = card("http://[image-location]", "Image alt");
    card.setHeader("Card header");
    card.setTitle("Card title");
    card.setText("Some quick example text");
    card.addLink("#", "Launch");
    model.addAttribute(card);
    
    //Carousel
    Carousel carousel = carousel("demoCarousel", slide("http://[img-location]"), slide("http://img-location"));
    carousel.setShowControls(true);
    carousel.setShowIndicators(true);
    model.addAttribute(carousel);
    
    //Dropdown
    Dropdown dropdown = dropdown("Toggle");
    dropdown.add(link("#", "First Link"));
    dropdown.setHeader("My header");
    model.addAttribute(dropdown);
    
    return "index";
}

Application html template:

<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:ui="http://www.thymeleaf.org/ui">
<body>
    <div ui:alert="${alert}"></div>
    <span ui:alert="${badge}"></span>
    <span class="badge badge-pill badge-primary" ui:alert="${badge2}"></span>
    <nav ui:breadcrumb="${breadcrumb}"></nav>
    <div ui:card="${card}"></div>
    <div ui:carousel="${carousel}"></div>
    <div ui:dropdown="${dropdown}"></div>
</body>
</html>

Note: the ui:render tag is able to render any Renderable object. Using ui:render="${alert}" produces the same output as ui:alert="${alert}"

Themes

Any component has an html template with some Thymeleaf logic, these templates are located under templates/ui/themes/[theme]/[class-name]-component.html.

The default theme is default based on Bootstrap 4.

Custom components

Define your custom components just extending io.github.thymeleaf.ui.Component and create the html template, an example of a new component:

public class CustomComponent extends Component {
    private final String message;

    public CustomComponent(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

Template file for this component src/main/resources/templates/ui/themes/[theme]/custom-component-component.html:

<div>
    <strong th:text="*{message}"></strong>
</div>

Spring MVC @Controller

@GetMapping("/index")
public String index(ModelMap model) {
    model.addAttribute(new CustomComponent("Hello world!"));
    
    return "index";
}

Application html template:

<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:ui="http://www.thymeleaf.org/ui">
<body>
    <div ui:render="${customComponent}"></div>
</body>
</html>

About

Thymeleaf dialect to create interface components bootstrap like

Resources

License

Stars

Watchers

Forks

Packages

No packages published