Smart UI with XMLUI Integration

Creating XMLUI HelloWorld Component & Using Smart UI for React

This document provides a complete guide on how to build and use the Smart with the XMLUI Framework. Visit the official XMLUI site

This tutorial demonstrates how to build a basic HelloWorld component using XMLUI and integrate Smart UI for React components into the same XMLUI-driven React application.

XMLUI components are made of three main parts:

  1. Native React component (HelloWorldNative.tsx) - The actual React implementation
  2. Component metadata (HelloWorld.tsx) - Describes props and integrates with XMLUI
  3. For visual components, a .scss file (HelloWorld.module.scss)
This separation allows XMLUI to understand your component's interface while maintaining clean React code.

Prerequisites

  1. Node.js 20+
  2. React + TypeScript knowledge
  3. Basic understanding of XMLUI markup & Smart UI

1. Create your project folders & Install Dependencies

md xmlui-hello-world
cd xmlui-hello-world

This creates a fresh project directory where you'll build your component from scratch.

npm install --save-dev xmlui
Now let's update the package.json with the proper configuration for our extension:
 {
  "name": "xmlui-hello-world",
  "version": "0.1.0",
  "type": "module",
  "scripts": {
    "build:extension": "xmlui build-lib"
  },
  "devDependencies": {
    "xmlui": "*"
  },
  "main": "./dist/xmlui-hello-world.js",
  "module": "./dist/xmlui-hello-world.mjs",
  "exports": {
    ".": {
      "import": "./dist/xmlui-hello-world.mjs",
      "require": "./dist/xmlui-hello-world.js"
    }
  },
  "files": [
    "dist"
  ]
}  

Now let's install Smart UI for React.

npm install xmlui smart-webcomponents-react

Smart UI components are standard React components. To use them in XMLUI, wrap them with XMLUI metadata just like custom components.

2. Project Structure

src/
├─ HelloWorldNative.tsx
├─ HelloWorld.tsx
├─ HelloWorld.module.scss
└─ index.tsx
text-app/
├─ index.html
└─ Main.xmlui

3. HelloWorld Native React Component(HelloWorldNative.tsx)

We will add the Smart.Table and Smart.Button components and enable the following Table features: Sorting, Filtering, Editing and Selection.
import React, { useState } from "react";
import styles from "./HelloWorld.module.scss";
import 'smart-webcomponents-react/source/styles/smart.default.css';
import { Button } from 'smart-webcomponents-react/button';
import { Table } from 'smart-webcomponents-react/table';

type Props = {
  id?: string;
  message?: string;
};

export const defaultProps = {
  message: "Hello, World!",
};

export function HelloWorld({
  id,
  message = defaultProps.message,
}: Props) {
  const [clickCount, setClickCount] = useState(0);

  const handleClick = () => {
    setClickCount(clickCount + 1);
  };

  return (
    <div className={styles.container} id={id}>
      <h2 className={styles.message}>{message}</h2>
      <Button onClick={handleClick}>
        Click me!
      </Button>
      <div className={styles.counter}>Clicks: {clickCount}</div>
	  <h3>Smart UI Table</h3>
	  <Table sortMode={"one"} filtering={true} filterRow={true} selection={true} editMode={"cell"}>
			<table>
				<thead>
					<tr>
						<th scope="col">Country</th>
						<th scope="col">Area</th>
						<th scope="col">Population_Rural</th>
						<th scope="col">Population_Total</th>
						<th scope="col">GDP_Total</th>
					</tr>
				</thead>
				<tbody>
					<tr>
						<td>Brazil</td>
						<td>8515767</td>
						<td>0.15</td>
						<td>205809000</td>
						<td>2353025</td>
					</tr>
					<tr>
						<td>China</td>
						<td>9388211</td>
						<td>0.46</td>
						<td>1375530000</td>
						<td>10380380</td>
					</tr>
					<tr>
						<td>France</td>
						<td>675417</td>
						<td>0.21</td>
						<td>64529000</td>
						<td>2846889</td>
					</tr>
					<tr>
						<td>Germany</td>
						<td>357021</td>
						<td>0.25</td>
						<td>81459000</td>
						<td>3859547</td>
					</tr>
					<tr>
						<td>India</td>
						<td>3287590</td>
						<td>0.68</td>
						<td>1286260000</td>
						<td>2047811</td>
					</tr>
					<tr>
						<td>Italy</td>
						<td>301230</td>
						<td>0.31</td>
						<td>60676361</td>
						<td>2147952</td>
					</tr>
					<tr>
						<td>Japan</td>
						<td>377835</td>
						<td>0.07</td>
						<td>126920000</td>
						<td>4616335</td>
					</tr>
					<tr>
						<td>Russia</td>
						<td>17098242</td>
						<td>0.26</td>
						<td>146544710</td>
						<td>1857461</td>
					</tr>
					<tr>
						<td>United States</td>
						<td>9147420</td>
						<td>0.19</td>
						<td>323097000</td>
						<td>17418925</td>
					</tr>
					<tr>
						<td>United Kingdom</td>
						<td>244820</td>
						<td>0.18</td>
						<td>65097000</td>
						<td>2945146</td>
					</tr>
				</tbody>
			</table>
		</Table>
    </div>
  );
}

4. Create basic styles (src/HelloWorld.module.scss)

.container {
  background-color: #f5f5f5;
  color: #333;
  padding: 1rem;
  border-radius: 8px;
  text-align: center;
  display: inline-block;
  min-width: 200px;
}

.message {
  margin: 0 0 1rem 0;
  font-size: 1.5rem;
}

.button {
  background-color: #4a90e2;
  color: white;
  border: none;
  padding: 0.75rem 1.5rem;
  border-radius: 4px;
  cursor: pointer;
  font-size: 1rem;
  margin-bottom: 1rem;

  &:hover {
    opacity: 0.9;
  }
}

.counter {
  font-size: 1.2rem;
  font-weight: bold;
}

5. XMLUI Metadata & Renderer (HelloWorld.tsx)

import styles from "./HelloWorld.module.scss";
import { createComponentRenderer, createMetadata } from "xmlui";
import { HelloWorld, defaultProps } from "./HelloWorldNative";

const HelloWorldMd = createMetadata({
  description: "`HelloWorld` is a demonstration component.",
  status: "experimental",
  props: {
    message: {
      description: "The message to display.",
      isRequired: false,
      type: "string",
      defaultValue: defaultProps.message,
    },
  },
});

export const helloWorldComponentRenderer = createComponentRenderer(
  "HelloWorld",
  HelloWorldMd,
  ({ node, extractValue }) => {
    return (
      <HelloWorld
        id={extractValue.asOptionalString(node.props?.id)}
        message={extractValue.asOptionalString(node.props?.message)}
      />
    );
  }
);


The renderer is the glue that translates XMLUI markup into React, making sure all props are correctly extracted and defaults are applied when needed.

6. Create the extension index (src/index.tsx )

import { helloWorldComponentRenderer } from "./HelloWorld";

export default {
  namespace: "XMLUIExtensions",
  components: [helloWorldComponentRenderer],
};
 

7. Build the extension

npm run build:extension

This creates xmlui-hello-world.js in the dist folder.


8. Test the application

Create the test-app/Main.xmlui file with your component's markup
<App>
  <VStack gap="2rem" padding="2rem">
    <Heading>HelloWorld Component Test</Heading>
    <HelloWorld message="Hello from standalone app!" />
  </VStack>
</App>

Then create the index.html file

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>HelloWorld Extension Test</title>
  <script src="https://unpkg.com/xmlui@latest/dist/standalone/xmlui-standalone.umd.js"></script>
  <script src="../dist/xmlui-hello-world.js"></script>
</head>
<body theme="dark">
</body>
</html>

9. Run the app


npx -y http-server -p 3000 -c-1 -o

Tip: This same wrapping pattern works for advanced Smart UI components like Grids, Charts, and Schedulers.

Summary

  • XMLUI separates metadata from React logic
  • Smart UI components can be wrapped and exposed to XMLUI
  • You can freely mix custom and third-party UI components

You now have a clean foundation for building structured XML-driven UIs powered by React and Smart UI.


Download the test app xmlui-demo.zip