The Unified UI Language with Flow-State Engine
One file. HTML + CSS + JS. Zero config. Write in English or code — your choice.
HJX is a compiled UI language that unifies structure, style, and logic into a single .hjx file. It compiles to clean, dependency-free HTML + CSS + JavaScript or React components — no virtual DOM, no runtime overhead, no framework lock-in.
Write UI in plain English. The Flow-State Engine translates natural language descriptions directly into HJX code. You can also mix English with code for a seamless development experience.
$ hjx flow "create a counter component"
✅ Generates complete HJX with state, layout, styles, and handlers
$ hjx flow "make a todo app"
✅ Full todo app with add/remove functionality
$ hjx flow --grammar custom.yml "build a dashboard"
✅ Use your own grammar rules for custom generationWrite styles in natural language:
style:
.card:
card
text align center
display flex
flex direction column
gap 24px
.button:
button primary
.button:hover:
box shadow medium
transition all 0.2s ease
Compile to React with one command:
$ hjx build todo-app.hjx --target react --backend
✅ Generates TodoApp.tsx + CSS modules + Express.js API routes- Node.js v18+
- npm v9+
# 1. Clone the repository
git clone https://github.com/loayabdalslam/hjx.git
cd hjx
# 2. Install dependencies
npm install
# 3. Build the compiler
npm run build
# 4. Flow-State: Generate HJX from natural language
node dist/cli.js flow "create a counter component"
# 5. Build an example
node dist/cli.js build examples/counter.hjx --out dist-app
# 6. Start the dev server (with hot reload)
node dist/cli.js dev examples/counter.hjx --out dist-app --port 5173Open http://localhost:5173 and you're live.
Describe what you want in English, get working HJX:
# Create components
hjx flow "create a counter component"
hjx flow "make a form with name and email fields"
hjx flow "build a todo list with add and delete"
# Add features
hjx flow "add state called count"
hjx flow "add button called Submit"
hjx flow "make the card centered with a shadow"
# Compile directly to HTML/CSS/JS
hjx flow --compile "create a counter with reset"Seamlessly blend natural English with HJX code:
create a dashboard component
state:
users = 0
revenue = 0
make the container centered with a card style
add a title that says "Analytics Dashboard"
add buttons for "View Reports" and "Export Data"
Take full control of the language with grammar.yml:
custom_rules:
rules:
- name: "my-component"
patterns:
- "make a {{1}} component"
- "build {{1}} widget"
template: |
component {{1|capitalize}}
state:
value = 0
layout:
view.card:
text: "{{1}}"
style:
.card:
card
handlers:hjx flow --grammar my-grammar.yml "make a weather widget"| Command | Output |
|---|---|
create a counter |
Counter with increment/decrement |
make a form |
Form with inputs, bindings, submit |
create a todo list |
Todo app with add/remove |
add state called X |
state: X = 0 |
add button called X |
button.primary: "X" |
make X centered |
Flexbox centering styles |
fetch from /api/X |
API endpoint definition |
Write styles using human-readable descriptions. The compiler translates your intent to proper CSS automatically.
style:
.container:
container # max-width: 1200px, margin: auto, padding
.card:
card # padding, background, border-radius, shadow
.primary-btn:
button primary # padding, background, color, border, cursor
.input-field:
input field # padding, border, font-size, width
| Natural Language | Generated CSS |
|---|---|
padding 16px |
padding: 16px; |
font size 24px |
font-size: 24px; |
display flex |
display: flex; |
justify content center |
justify-content: center; |
box shadow light |
box-shadow: 0 2px 8px rgba(0,0,0,0.1); |
border radius 12px |
border-radius: 12px; |
transition all 0.3s ease |
transition: all 0.3s ease; |
breakpoints:
mobile = 480px
tablet = 768px
style:
.button:
button primary
.button:hover:
background #0056b3
box shadow medium
.container @mobile:
padding 12px
flex direction column
Compile HJX directly to React components:
hjx build counter.hjx --target reactCounter.tsx:
import React, { useState } from 'react';
import styles from './Counter.module.css';
export function Counter() {
const [count, setCount] = useState(0);
function inc() { setCount(count + 1); }
function dec() { setCount(count - 1); }
return (
<view className={styles.card} id="root">
<text className={styles.title}>Count: {count}</text>
<button className={styles.primary} onClick={() => inc()}>Increase</button>
<button className={styles.secondary} onClick={() => dec()}>Decrease</button>
</view>
);
}Counter.module.css:
[data-hjx-scope="hjx-counter"] .card {
padding: 16px;
background: white;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
/* ... */
}hjx build todo-app.hjx --target react --backendGenerates:
TodoApp.tsx— React component with API callsTodoApp.module.css— Scoped CSS modulesapi/routes.ts— Express.js routesapi/handlers.ts— API handler functions with TypeScript
Define API endpoints directly in HJX:
api:
GET /api/todos -> fetchTodos:
query:
page = 1
limit = 10
POST /api/todos -> createTodo:
body:
text = string
done = boolean
DELETE /api/todos/:id -> deleteTodo:
params:
id = number
Use in handlers:
handlers:
loadData:
fetch fetchTodos -> todos
set items = todos
addItem:
fetch createTodo with { text: newItem } -> result
set items = [...items, result]
set newItem = ""
Every .hjx file follows this block structure:
component <Name> ← Component declaration
imports: ← Optional: import other .hjx components
state: ← Reactive variables
api: ← Optional: REST API endpoints
layout: ← UI tree (indentation-based)
style: ← Natural language CSS or raw CSS
breakpoints: ← Optional: custom media breakpoints
handlers: ← Event logic
script: ← Optional: server-side code
component Counter
state:
count = 0
layout:
view#root.card:
text.title: "Count: {{count}}"
button.primary (on click -> inc): "Increase"
button.secondary (on click -> dec): "Decrease"
style:
.card:
padding 16px
border 1px solid #ddd
border radius 12px
text align center
.primary:
button primary
.secondary:
button secondary
handlers:
inc:
set count = count + 1
dec:
set count = count - 1
That's it. One file → a fully working interactive counter. No imports, no boilerplate, no configuration.
state:
count = 0 # Number
name = "John" # String
active = true # Boolean
items = ["a", "b"] # Array
user = { name: "John" } # Object
| Syntax | Description |
|---|---|
view |
Generic container (<div>) |
text |
Inline text (<span>) |
button |
Button element |
input |
Input element |
view#id.class1.class2: |
ID + classes |
text: "Hello {{name}}" |
Text interpolation |
button (on click -> handler): "Label" |
Event binding |
input (bind value <-> stateVar) |
Two-way binding |
layout:
if (isLoggedIn):
text: "Welcome back!"
for (item in items):
view.row:
text: "{{item}}"
handlers:
increment:
set count = count + 1
reset:
set count = 0
log "Counter reset"
| Command | Description |
|---|---|
hjx parse <file.hjx> |
Print the AST (JSON) for a file |
hjx build <file.hjx> --out <dir> |
Compile to vanilla HTML/CSS/JS |
hjx build <file.hjx> --out <dir> --target react |
Compile to React component |
hjx build <file.hjx> --out <dir> --target react --backend |
Compile to React + Express backend |
hjx dev <file.hjx> --out <dir> --port <n> |
Build, serve, and watch with hot reload |
hjx flow "description" |
Generate HJX from natural language |
hjx flow --file input.txt |
Read input from file |
hjx flow --grammar custom.yml "desc" |
Use custom grammar rules |
hjx flow --compile "desc" |
Compile directly to HTML/CSS/JS |
Benchmarked on Windows x64 • Node.js • JSDOM environment Date: 2026-02-17
| Workload | Time |
|---|---|
| Parse 100 state variables | 2.15 ms |
| Parse 1,000 state variables | 1.90 ms |
| Parse 5,000 state variables | 11.25 ms |
| Parse 100 static nodes | 0.95 ms |
| Parse 1,000 static nodes | 2.55 ms |
| Parse 5,000 static nodes | 17.12 ms |
| Workload | Time |
|---|---|
| Compile 100 nodes → Vanilla JS | 1.73 ms |
| Compile 1,000 nodes → Vanilla JS | 2.87 ms |
| Compile 5,000 nodes → Vanilla JS | 13.19 ms |
| Scope 100 CSS rules | 0.33 ms |
| Scope 1,000 CSS rules | 1.86 ms |
| Input | Intent Match | Generation Time |
|---|---|---|
| "create a counter" | counter (98%) | < 5ms |
| "make a form" | form (95%) | < 5ms |
| "create a todo list" | todo-list (95%) | < 5ms |
| Mixed code + English | mixed (80%) | < 10ms |
| Workload | Render | Update |
|---|---|---|
| Static 100 items | 33 ms | — |
| Static 1,000 items | 135 ms | — |
| List 100 items | 59 ms | 27 ms |
| List 1,000 items | 286 ms | 217 ms |
| Conditional 100 items | 142 ms | 2 ms |
| Conditional 1,000 items | 8,057 ms | 14 ms |
| Text interpolation 100 items | 46 ms | 2 ms |
| Input binding 100 items | 63 ms | 1 ms |
Key insight: Updates are extremely fast (sub-3ms for 100 items) thanks to targeted DOM patching.
hjx/
├── src/
│ ├── cli.ts # CLI entry point
│ ├── parser.ts # HJX → AST
│ ├── compiler/
│ │ ├── vanilla.ts # Vanilla JS target
│ │ ├── react.ts # React target (NEW)
│ │ ├── nl_css.ts # Natural language CSS (NEW)
│ │ └── server_driven.ts # Server-driven target
│ ├── nlp/
│ │ ├── flow/ # Flow-State Engine (NEW)
│ │ │ ├── flow_engine.ts
│ │ │ ├── grammar_loader.ts
│ │ │ └── cli.ts
│ │ ├── tokenizer/ # HJX tokenizer
│ │ ├── parser/ # Enhanced parser
│ │ ├── intent/ # Intent classifier
│ │ ├── entities/ # Entity extraction
│ │ ├── features/ # Feature extraction
│ │ ├── completion/ # Code completion
│ │ ├── generation/ # Code generation
│ │ └── errors/ # Error detection
│ └── lovable/ # AI integration
├── examples/
│ ├── counter.hjx
│ ├── counter_v2.hjx # Natural language CSS
│ ├── todo-app.hjx # With API integration
│ ├── dashboard_v2.hjx # Grid layouts
│ └── components/
├── grammar.yml # User-editable grammar (NEW)
├── docs/ # VitePress documentation
├── extensions/vscode/ # VS Code extension
├── packages/vite-plugin-hjx/ # Vite plugin
└── package.json
npm install vite-plugin-hjx --save-dev// vite.config.js
import { defineConfig } from 'vite';
import hjxPlugin from 'vite-plugin-hjx';
export default defineConfig({
plugins: [hjxPlugin()]
});Syntax highlighting, snippets, and (coming soon) Flow-State integration.
# Install from extensions/vscode/
code --install-extensions extensions/vscode/hjx-vscode-0.1.0.vsixPRs are welcome! If you'd like to contribute:
- Fork the repository
- Create a feature branch (
git checkout -b feature/my-feature) - Commit your changes (
git commit -m 'Add my feature') - Push to the branch (
git push origin feature/my-feature) - Open a Pull Request
- Edit
grammar.ymlin the project root - Add your patterns under
custom_rules: - Test with:
hjx flow --grammar grammar.yml "your description"
MIT © Loay Abdalslam