While migrating from one of our React-based portlets to a React Client Extension in Liferay DXP, I encountered a recurring challenge: how to properly provide portlet-level configurations within client extensions. In traditional portlets, configuring screens is straightforward. However, when moving to client extensions, especially React client extensions, the approach changes significantly.
If you’re new to client extensions, check out our earlier blog, Mastering Liferay Client Extension Development: Comprehensive Guide.
During this migration, I realized that the default way of passing properties to client extensions (using simple key-value pairs) isn't ideal. Not only is it unintuitive for non-technical users, but it also lacks support for user-friendly field types like checkboxes, radio buttons, and text inputs. This makes the configuration process difficult for content authors and administrators.
Fortunately, Liferay provides a cleaner and more flexible solution: Fragment Configurations. By leveraging these, we can offer structured, user-friendly configuration interfaces and seamlessly pass those values into our React client extension.
The Problem
By default, properties can be passed to client extensions using key-value pairs in the configuration. However, this method has two key limitations:
- Non-technical users may find it challenging to input the right keys and values.
- We can't easily display user-friendly field types like checkboxes, radio buttons, or text inputs.
This makes configuration tricky for content authors and administrators.
The solution? We can leverage Fragment Configurations. Fragments allow us to define configurations in a structured way (with labels, input types, validations, etc.) and then pass those values to the client extension. This approach provides a cleaner, user-friendly interface for configuration while still integrating seamlessly with client extensions.
Let’s walk through the steps.
Step 1: Create the Client Extension JS Import Map
First, we need to create a JS Import Maps Entry that points to the JavaScript file of our client extension. This allows us to import it inside a fragment.
Example:
test-app-js-importer:
bareSpecifier: test-app-js-importer
name: Test React App JS Importer
type: jsImportMapsEntry
url: http://localhost:4173/assets/index-yv.js
Here:
- bareSpecifier → the name we’ll use when importing the extension
- url → points to the frontend app’s bundled JS file
Step 2: Import the Client Extension into a Fragment
Next, create a new fragment in Liferay. Inside the JS section, import the client extension using the bareSpecifier:
import "test-app-js-importer"
Step 3: Define Fragment Configurations
Instead of raw key–value pairs, we now define structured fragment configurations. These fields will appear in the fragment’s configuration panel in Liferay.
{
"fieldSets": [
{
"fields": [
{
"dataType": "string",
"label": "Category ID",
"name": "CATEGORYID",
"description": "Enter the category ID for uploaded documents",
"type": "text"
},
{
"label": "Enable Preview",
"name": "ENABLEPREVIEW",
"description": "Toggle document preview option",
"type": "checkbox",
"default": false
}
],
"label": "Test App Configurations"
}
]
}
Now, instead of guessing keys and values, users get:
- A text input for Category ID
- A checkbox to enable/disable preview
Step 4: Use the Configurations in the Fragment HTML
Once we have configurations, we can pass them to the client extension via attributes on the custom element.
<test-app-web-component
CATEGORY_ID="${configuration.CATEGORYID}"
ENABLE_PREVIEW= "${configuration.ENABLEPREVIEW?string('true', 'false')}">
</test-app-web-component>
This connects the user-friendly fragment configuration fields directly to the client's extension.
Step 5: Apply CSS for the Client Extension
By default, the client extension CSS may not load inside the fragment.
Bundle the CSS in the extension build, so it automatically applies when the JS is loaded.
Step 6: Deploy the Fragment on a Page
Now edit your page, drag and drop your fragment onto the layout, and click on the fragment. You’ll see the configuration panel appear on the right-hand side, where you can set values for each configuration field.
Once configured, you can access those values inside your React client extension using the following code:
const properties = {
categoryId: this.getAttribute("CATEGORY_ID"),
enablePreview: this.getAttribute("ENABLE_PREVIEW")
};
You can then pass this properties object into your React app and use it anywhere, for example:
<h3>Value of Category Id : {properties.categoryId}</h3>
<h3>Value of Preview Enable : {properties.enablePreview}</h3>

Conclusion
By integrating fragment configurations with client extensions, we unlock:
A user-friendly configuration panel (with text inputs, checkboxes, etc.)
The ability to pass these configurations seamlessly into custom elements
A more flexible and maintainable approach than raw key–value configurations.
This approach bridges the gap between technical setup and non-technical usability, making client extensions much more accessible for content authors.
FAQs
1. What is the main benefit of using Fragment Configurations with client extensions?
Fragment Configurations provide a user-friendly interface with proper input fields, making configuration easier for non-technical users.
2. Can I pass multiple configuration values to my React client extension?
Yes. Any field defined in the Fragment Configuration can be passed as an HTML attribute to your client extension.
3. Do I need to write backend code to support fragment configurations?
No. Fragment configurations work entirely on the frontend and are handled by Liferay’s fragment framework.
4. Why isn’t my client extension CSS loading inside the fragment?
Client-extension CSS must be bundled with the JavaScript to build. Once bundled, it loads automatically when the JS executes.
5. Can I update configuration values without redeploying the client extension?
Yes. Since configurations are handled at the fragment level, you can modify them directly in the page editor without redeployment.