Custom element client extensions use Liferay’s frontend infrastructure to register external applications with the Liferay platform and render them as widgets. For applications that include multiple routes (e.g., React Router), you can define remote application properties to determine which routes are used for a widget at runtime. These properties can be set for an application via the Remote Apps menu in Liferay or the widget’s configuration options once deployed.
Warning
Deploying Custom elements or IFrames like other types of client extensions is a beta feature in Liferay 7.4. This tutorial deploys custom element remote applications differently, and it is still the recommended approach until a future update.
In this tutorial, create a basic React application using Liferay’s create_custom_element.sh script, which generates a sample app with three routes: hello-world, hello-foo, hello-bar. After compiling the application and hosting its .js and .css files, register the application with Liferay and deploy it as a page widget. Finally, configure it to use each of the alternative routes.
Note
Custom element client extensions can use any technology, regardless of how it’s built, packaged, or hosted. This tutorial only offers a sample custom element application with basic routing.
Running create_custom_element.sh requires the latest versions of Node.JS, NPM, and YARN. Before proceeding, ensure these tools are installed.
Navigate to the new j1v3-custom-element folder and build the application.
cd j1v3-custom-element
yarn build
Verify the build succeeded and note the application’s .js and .css files.
Creating an optimized production build...
Compiled successfully.
File sizes after gzip:
43.51 kB build/static/js/main.114dde4a.js
121 B build/static/css/main.9877909d.css
Sign in to Liferay at <http://localhost:8080> using the email address test@liferay.com and the password test. When prompted, change the password to learn.
Open the Site Menu (), expand Content & Data, and go to Documents and Media.
Click Add () and select Multiple Files Upload.
Drag and drop the .js and .css files into the upload area.
Click Publish.
This adds the files to the Liferay Document Library and assigns them unique WebDAV URLs, which you use to create the remote application.
Tip
This tutorial hosts the application’s static resources in Liferay’s Document Library for demonstration purposes. In a production environment, you should host the application’s files on a server optimized for hosting static resources.
To view each file’s URL, click the Info icon () and select one of the files at a time. Copy each file’s WebDAV URL and save them for use in the next step.
Open the Global Menu (), click on the Applications tab, and go to Remote Apps.
Click Add ().
Enter these values:
Field
Value
Name
J1V3-Custom-Element
Type
Custom Element
HTML Element Name
j1v3-custom-element
URL
WebDAV URL for the .js file
CSS URL
WebDAV URL for the .css file
Instanceable
✔
Portlet Category Name
Remote Apps
Click Save.
Once saved, Liferay creates a widget named J1V3-Custom-Element, which you can deploy to Site Pages like any other Page widget. It appears under the selected Portlet Category Name.
Since J1V3-Custom-Element is instanceable, you can add many of them to a page, each with its own independent configuration. For this example, add the widget to a page twice.
The auto-generated app includes three routes: hello-world, hello-foo, hello-bar. By default the application uses the hello-world route. However, you can use remote application properties to configure it to use an alternate route. You can set these properties via the Remote Apps menu or a widget’s configuration options.
import React from 'react';
import {createRoot} from 'react-dom/client';
import api from './common/services/liferay/api';
import {Liferay} from './common/services/liferay/liferay';
import HelloBar from './routes/hello-bar/pages/HelloBar';
import HelloFoo from './routes/hello-foo/pages/HelloFoo';
import HelloWorld from './routes/hello-world/pages/HelloWorld';
import './common/styles/index.scss';
const App = ({route}) => {
if (route === 'hello-bar') {
return <HelloBar />;
}
if (route === 'hello-foo') {
return <HelloFoo />;
}
return (
<div>
<HelloWorld />
</div>
);
};
class WebComponent extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
createRoot(this).render(
<App
route={this.getAttribute('route')}
/>,
this
);
if (Liferay.ThemeDisplay.isSignedIn()) {
api('o/headless-admin-user/v1.0/my-user-account')
.then((response) => response.json())
.then((response) => {
if (response.givenName) {
const nameElements = document.getElementsByClassName(
'hello-world-name'
);
if (nameElements.length) {
nameElements[0].innerHTML = response.givenName;
}
}
});
}
}
}
const ELEMENT_ID = 'j1v3-custom-element';
if (!customElements.get(ELEMENT_ID)) {
customElements.define(ELEMENT_ID, WebComponent);
}
This index.js file creates the WebComponent class, which extends the HTMLElement interface. This class implements the interface’s connectedCallback() function, which calls ReactDOM.render with App as a parameter. When App is called, it checks for any defined "route" attribute and compares that value with the available routes. If it matches either hello-foo or hello-bar, it returns and renders the corresponding route. Otherwise, it returns and renders hello-world.
Each of the routes is imported into the index.js file from the routes folder:
This website uses cookies and similar tools, some of which are provided by third parties (together “tools”). These tools enable us and the third parties to access and record certain user-related and activity data and to track your interactions with this website. These tools and the informationcollected are used to operate and secure this website, enhance performance, enable certain website features and functionality, analyze and improve website performance, and personalize user experience.
If you click “Accept All”, you allow the deployment of all these tools and collection of the information by us and the third parties for all these purposes.
If you click “Decline All” your IP address and other information may still be collected but only by tools (including third party tools) that are necessary to operate, secure and enable default website features and functionalities. Review and change your preferences by clicking the “Configurations” at any time.
Visit our Privacy Policy