Creating Web Component
You can create Web Components from scratch based on Polymer 3 or Lit libraries. After a JavaScript Web Component is implemented, you can create a Java API for it.
The example below shows how to build the light/dark theme toggle based on Lit.
Creating JavaScript Web Component
Create the theme-toggle.js
file in the frontend/src/component/theme-toggle
folder. It contains a Web Component implementing the light/dark theme toggle.
import {html, LitElement} from 'lit';
import {PolylitMixin} from '@vaadin/component-base/src/polylit-mixin.js';
import {defineCustomElement} from '@vaadin/component-base/src/define.js';
import {ElementMixin} from '@vaadin/component-base/src/element-mixin.js';
import {TooltipController} from "@vaadin/component-base/src/tooltip-controller";
import {css, ThemableMixin} from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
import {buttonStyles} from '@vaadin/button/src/vaadin-button-base.js';
import {button as buttonLumoStyles} from '@vaadin/button/theme/lumo/vaadin-button-styles.js';
import {ButtonMixin} from '@vaadin/button/src/vaadin-button-mixin.js';
const themeToggleStyles = css`
:host {
background: transparent;
color: var(--lumo-text-color);
min-width: var(--lumo-button-size);
padding-left: calc(var(--lumo-button-size) / 4);
padding-right: calc(var(--lumo-button-size) / 4);
}
`;
class ThemeToggle extends ButtonMixin(ElementMixin(ThemableMixin(PolylitMixin(LitElement)))) { (1)
static get is() {
return 'theme-toggle'; (2)
}
static get styles() { (3)
return [buttonStyles, buttonLumoStyles, themeToggleStyles];
}
render() { (4)
return html`
<div class="vaadin-button-container">
<vaadin-icon icon="vaadin:adjust"></vaadin-icon>
</div>
<slot name="tooltip"></slot>
`;
}
static get properties() { (5)
return {
ariaLabel: {
type: String,
value: 'Theme toggle',
reflectToAttribute: true,
}
};
}
constructor() {
super();
this._storageKey = "app-theme";
this.addEventListener('click', () => this.toggleTheme());
}
/** @protected */
ready() {
super.ready();
this._tooltipController = new TooltipController(this); (6)
this.addController(this._tooltipController);
this.applyStorageTheme();
}
applyStorageTheme() {
let storageTheme = this.getStorageTheme();
let currentTheme = this.getCurrentTheme();
if (storageTheme && currentTheme !== storageTheme) {
this.applyTheme(storageTheme);
}
}
getStorageTheme() {
return localStorage.getItem(this._storageKey);
}
getCurrentTheme() {
return document.documentElement.getAttribute("theme");
}
toggleTheme() {
const theme = this.getCurrentTheme();
this.applyTheme(theme === "dark" ? "" : "dark");
}
applyTheme(theme) {
document.documentElement.setAttribute("theme", theme);
localStorage.setItem(this._storageKey, theme);
const customEvent = new CustomEvent('theme-changed', {detail: {value: theme}});
this.dispatchEvent(customEvent); (7)
}
}
defineCustomElement(ThemeToggle); (8)
export {ThemeToggle};
1 | Defines base classes for custom components. Since ThemeToggle needs to look and behave like a button, one of the base classes is ButtonMixin , which provides properties and handlers specific to buttons. |
2 | Defines the name of HTML element. |
3 | Defines styles of the component as a combination of imported vaadin-button styles and custom styles. |
4 | Defines Shadow DOM template |
5 | Defines custom properties. |
6 | Initializes TooltipController class that handles tooltip changes. Controller classes are used as delegates for repetitive functionality of visual components. |
7 | Dispatches custom event with the theme-changed name. |
8 | Exports custom HTML element with the name defined in the static get is() method. |
Creating Java API for Web Component
Create the ThemeToggle.java
file which is a UI component class. It defines an API for the server code, accessor methods, event listeners, and data sources connection.
import com.vaadin.flow.component.*;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.shared.HasTooltip;
import com.vaadin.flow.shared.Registration;
@Tag("theme-toggle") (1)
@JsModule("./src/component/theme-toggle/theme-toggle.js") (2)
public class ThemeToggle extends Component implements ClickNotifier<ThemeToggle>,
Focusable<ThemeToggle>, HasTheme, HasEnabled, HasSize, HasStyle, HasTooltip, HasAriaLabel { (3)
public ThemeToggle() {
}
public Registration addThemeChangeListener(ComponentEventListener<ThemeToggleThemeChangedEvent> listener) {
return addListener(ThemeToggleThemeChangedEvent.class, listener);
}
@DomEvent("theme-changed") (4)
public static class ThemeToggleThemeChangedEvent extends ComponentEvent<ThemeToggle> {
protected String value;
public ThemeToggleThemeChangedEvent(ThemeToggle source, boolean fromClient,
@EventData("event.detail.value") String value) { (5)
super(source, fromClient);
this.value = value;
}
public String getValue() {
return value;
}
}
}
1 | Defines the root element that is created automatically by the Component class and can be accessed using the getElement() method. Must be the same as the Web Component exports. |
2 | The @JsModule annotation defines the import of the JavaScript module. |
3 | Using Vaadin Mixin Interfaces to provide common APIs and default behavior for sets of functionalities found in most Web Components. |
4 | Using the @DomEvent annotation to connect a ThemeToggle component to the theme-changed DOM event. |
5 | Using the @EventData annotation to define additional event data, the theme value in this case. |
More information about creating custom components can be found in Vaadin documentation: Creating Components, Using Vaadin Mixin Interfaces, Using Events with Components&. |
Usage Example
After a component is implemented it can be used in views, for example:
@Subscribe
public void onInit(final InitEvent event) {
ThemeToggle themeToggle = new ThemeToggle();
getContent().add(themeToggle);
}
![theme toggle usage](../../_images/visual-components/creating-components/theme-toggle-usage.gif)
Was this page helpful?
Thank you for your feedback