JSX Templating

templates for TypeScript objects, using HTML syntax

Project Forge includes a lightweight, custom JSX engine that enables you to write component-based UI code using familiar JSX syntax. This implementation is designed to be minimal, fast, and dependency-free while providing the core benefits of JSX for dynamic content generation.

Overview

The JSX engine allows you to: - Write declarative UI components using JSX syntax - Create dynamic HTML elements programmatically - Build reusable component functions - Generate DOM elements that can be inserted into your pages

Unlike full frameworks like React, this JSX implementation focuses on simple DOM element creation without virtual DOM, state management, or lifecycle methods. It’s perfect for progressive enhancement and dynamic content generation.

Getting Started

To use JSX in your project, create a .tsx file in ./client/src and use Project Forge to import the jsx module into your application:

1
2
3
4
5
import * as JSX from "./jsx";

export function myComponent() {
return <div>Check out this JSX!</div>;
}

Basic Usage

Simple Elements

Create basic HTML elements with JSX syntax:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import * as JSX from "./jsx";

// Simple div element
function createContainer() {
return <div className="container">Hello World</div>;
}

// Element with multiple attributes
function createButton() {
return <button type="button" className="btn btn-primary" disabled>
Click Me
</button>;
}

// Element with inline styles
function createStyledElement() {
return <div style="color: red; font-weight: bold;">
Important Message
</div>;
}

Elements with Content

JSX supports various types of content including text, other elements, and arrays:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import * as JSX from "./jsx";

// Text content
function createHeading() {
return <h1>Welcome to Project Forge</h1>;
}

// Nested elements
function createCard() {
return (
<div className="card">
<div className="card-header">
<h3>Card Title</h3>
</div>
<div className="card-body">
<p>This is the card content.</p>
</div>
</div>
);
}

// Mixed content
function createMixedContent() {
return (
<div>
<h2>Features</h2>
<ul>
<li>Fast and lightweight</li>
<li>No external dependencies</li>
<li>TypeScript support</li>
</ul>
</div>
);
}

Advanced Features

Dynamic Content

Generate content dynamically using JavaScript expressions:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import * as JSX from "./jsx";

function createUserProfile(user: {name: string, email: string, isAdmin: boolean}) {
return (
<div className="user-profile">
<h2>{user.name}</h2>
<p>Email: {user.email}</p>
{user.isAdmin && <span className="badge">Admin</span>}
</div>
);
}

function createItemList(items: string[]) {
return (
<ul>
{items.map(item => <li key={item}>{item}</li>)}
</ul>
);
}

Conditional Rendering

Use JavaScript expressions for conditional rendering:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import * as JSX from "./jsx";

function createStatusMessage(isLoading: boolean, error?: string, data?: any) {
if (isLoading) {
return <div className="loading">Loading...</div>;
}

if (error) {
return <div className="error">Error: {error}</div>;
}

if (data) {
return <div className="success">Data loaded successfully!</div>;
}

return <div className="info">No data available</div>;
}

function createConditionalButton(showButton: boolean, isEnabled: boolean) {
return (
<div>
{showButton && (
<button disabled={!isEnabled} className="btn">
{isEnabled ? "Click Me" : "Disabled"}
</button>
)}
</div>
);
}

Dangerous HTML

For cases where you need to insert raw HTML (use with caution):

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
import * as JSX from "./jsx";

function createRichContent(htmlContent: string) {
return (
<div
className="rich-content"
dangerouslySetInnerHTML={{__html: htmlContent}}
/>
);
}

// Example usage
const markdownHTML = "<p>This is <strong>bold</strong> text from markdown.</p>";
const contentElement = createRichContent(markdownHTML);

⚠️ Security Warning: Only use dangerouslySetInnerHTML with trusted content to prevent XSS attacks.

Component Patterns

Create reusable component functions:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import * as JSX from "./jsx";

// Button component with variants
function Button(props: {
text: string;
variant?: 'primary' | 'secondary' | 'danger';
onClick?: () => void;
disabled?: boolean;
}) {
const className = `btn btn-${props.variant || 'primary'}`;

const element = (
<button
className={className}
disabled={props.disabled}
type="button"
>
{props.text}
</button>
);

if (props.onClick) {
(element as HTMLButtonElement).addEventListener('click', props.onClick);
}

return element;
}

// Card component
function Card(props: {title: string, children: Node[]}) {
return (
<div className="card">
<div className="card-header">
<h3>{props.title}</h3>
</div>
<div className="card-body">
{props.children}
</div>
</div>
);
}

Limitations

This JSX implementation is intentionally minimal and has some limitations compared to full frameworks:

  • No virtual DOM or diffing algorithm
  • No built-in state management
  • No lifecycle methods
  • No component re-rendering
  • Limited to DOM element creation

These limitations make it perfect for progressive enhancement and dynamic content generation without the overhead of a full framework.