Deploying Clarity's Ticket List Custom Element
Clarity needs an application that allows distributors to view, filter, and expand their open and in-progress tickets. Clarity’s development team is familiar with the React framework and prefers to use it in their frontend implementations. With Liferay’s plug-and-play capabilities, they can continue using React without compromising Liferay’s updates or upgrades.
In this exercise, you’ll explore and deploy a React application developed by Clarity’s team as a custom element client extension to retrieve, filter, and display ticket data.
-
Open a file explorer and navigate to the
exercises/module-1/
folder in your course workspace. -
Rename the
react-app/
folder toclarity-ticketing-ui
.
This is our application folder, which we will transform into a client extension. -
Open the
clarity-ticketing-ui/webpack.config.js
file and paste the following code./** * SPDX-FileCopyrightText: (c) 2000 Liferay, Inc. https://liferay.com * SPDX-License-Identifier: LGPL-2.1-or-later OR LicenseRef-Liferay-DXP-EULA-2.0.0-2023-06 */ const path = require('path'); const webpack = require('webpack'); const DEVELOPMENT = process.env.NODE_ENV === 'development'; const WEBPACK_SERVE = !!process.env.WEBPACK_SERVE; module.exports = { devServer: { headers: { 'Access-Control-Allow-Origin': '*', }, port: 3000, }, devtool: DEVELOPMENT ? 'source-map' : false, entry: { index: './index.js', }, externals: { 'react': 'react', 'react-dom': 'react-dom', }, experiments: { outputModule: true, }, mode: DEVELOPMENT ? 'development' : 'production', module: { rules: [ { test: /\.(js|jsx)$/, // Process .js and .jsx files exclude: /node_modules/, // Exclude dependencies use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env', '@babel/preset-react'], }, }, }, { test: /\.css$/, // Process .css files use: ['style-loader', 'css-loader'], }, ], }, resolve: { extensions: ['.js', '.jsx'], // Add .jsx to extensions }, optimization: { minimize: !DEVELOPMENT, }, output: { clean: true, environment: { dynamicImport: true, module: true, }, filename: WEBPACK_SERVE ? '[name].js' : '[name].[contenthash].js', //Here we set the library format, which specifies how the output bundle should be exposed library: { type: 'module', }, path: path.resolve('build', 'static'), }, plugins: [ new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1, }), ], };
Note that we’ve added the
library
format, which specifies how the output bundle should be exposed. -
Save the file.
-
From the
clarity-ticketing-ui/public
folder, open theindex.html
file in a text editor or IDE. -
Replace the
<root>
and the<tickets-root>
tags with a<clarity-ticketing-ui>
tag, the name of our custom element.
Your final result should look like this:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Clarity Ticketing UI</title> </head> <body> <clarity-ticketing-ui></clarity-ticketing-ui> <script type="module" src="build/static/index.js"></script> </body> </html>
-
Save the file.
-
Paste the following code into the
clarity-ticketing-ui/index.js
file.import React, { useState, useEffect } from 'react'; import ReactDOM, { render } from 'react-dom'; import './assets/style.css'; import TicketsList from './assets/components/TicketsList'; import { HashRouter, Route, Routes } from "react-router-dom"; import App from './App'; // Custom Element class class CustomElement extends HTMLElement { connectedCallback() { // Ensure the React component is rendered only once if (!this.rendered) { // Create a container if it doesn't exist const container = document.createElement('div'); container.id = 'tickets-root'; this.appendChild(container); // Render the React component into the container ReactDOM.render(<TicketsList />, container); this.rendered = true; } } disconnectedCallback() { // Clean up the React component when the element is removed const container = this.querySelector('#tickets-root'); if (container) { ReactDOM.unmountComponentAtNode(container); } this.rendered = false; } } // Define the custom element const ELEMENT_NAME = 'clarity-ticketing-ui'; if (!customElements.get(ELEMENT_NAME)) { customElements.define(ELEMENT_NAME, CustomElement); } // Automatically add the custom element to the page if not already present document.addEventListener('DOMContentLoaded', () => { if (!document.querySelector(ELEMENT_NAME)) { const customElement = document.createElement(ELEMENT_NAME); document.body.appendChild(customElement); } });
This replaces the default use of
render()
on theticket-root
div, leveraging a Web Component to define the React app as a reusable and self-contained custom element. -
Save the file.
-
Create a new file named
client-extension.yaml
in theclarity-ticketing-ui/
folder and add the following code.assemble: - from: build/static into: static clarity-ticketing-ui: friendlyURLMapping: clarity-ticketing-ui htmlElementName: clarity-ticketing-ui instanceable: false name: Clarity Ticketing UI portletCategoryName: category.client-extensions type: customElement urls: - index.*.js useESM: true
-
Move the
clarity-ticketing-ui/
folder into theclient-extensions/
folder within your course workspace. -
Open a terminal and navigate to the
client-extensions/clarity-ticketing-ui/
folder. -
Run this command to build and deploy the custom element client extension:
blade gw clean deploy
-
Verify that the client extension deploys successfully:
2025-01-28 11:50:59.076 INFO [fileinstall-directory-watcher][BundleStartStopLogger:68] STARTED clarityticketingui_7.4.13 [1462]
Now that you've deployed the custom element client extension, examine the ticketing app UI.
-
In your Liferay instance, sign in as the Clarity Admin user.
-
Username:
admin@clarityvisionsolutions.com
-
Password:
learn
-
-
Open the Site Menu (
), click Page Tree, and select the Tickets page. -
Click Edit (
) to start editing the page. -
In the Fragments and Widgets search bar, search for
Clarity Ticketing UI
. -
Drag and drop the Clarity Ticketing UI widget to the page.
-
Click Publish.
You've now learned how to deploy custom element client extensions, giving you more control over your application.
Conclusion
Great! You’ve successfully deployed a custom element client extension for retrieving and displaying Clarity’s ticket data. Next, you’ll learn about a different use case for custom elements as remote applications.
Capabilities
Product
Education
Contact Us