This directory contains examples that demonstrate client-side functionality using jsgui3-server for server-side rendering and development. These examples are specifically designed to show how jsgui3-html works in an isomorphic (server + client) context.
These examples require jsgui3-server which is listed as a devDependency only. This means:
- They demonstrate client-side capabilities in a realistic server context
- They showcase server-side rendering + client-side activation patterns
- They don't add
jsgui3-serverto production dependencies - The main
examples/directory contains standalone examples that don't require a server
- Install all dependencies including devDependencies:
npm install- The
jsgui3-serverpackage will be installed automatically
Each example has its own server script. To run an example:
# From the jsgui3-html root directory
node dev-examples/binding/counter/server.js
# Or from within the example directory
cd dev-examples/binding/counter
node server.jsThen open your browser to http://localhost:52000 (or the port shown in console).
Demonstrate MVVM data binding with server-side rendering:
- counter/ - Simple counter with server-side rendering and client-side activation
- user-form/ - Form with server-side validation API
- missing-controls/ - New core controls demo (inputs, indicators, navigation, feedback)
- data-controls/ - Data table, data grid, virtualization, and collection controls
- layout-controls/ - Layout and navigation controls (split pane, tabs, drawer, stepper)
- form_editor_features/ - Form container, validation, input masks, autosize, rich text, object editor
- showcase_app/ - Polished control showcase with live Theme Studio (preset + token editor)
Demonstrates Activation tiers for native controls:
- progressive/ - Tier 0 (native), Tier 1 (styled), Tier 2 (activated), and mixed activation markers
// server.js
const Server = require('jsgui3-server');
const jsgui = require('./client');
const server = new Server({
Ctrl: jsgui.controls.Demo_UI,
src_path_client_js: require.resolve('./client.js')
});
server.on('ready', () => {
server.start(52000, (err) => {
if (err) throw err;
console.log('Server started on port 52000');
});
});The server:
- Renders the control to HTML on the server
- Bundles the client-side JavaScript
- Sends HTML with embedded data to the client
- Client JavaScript activates the DOM, attaching event handlers
// server.js
server.on('ready', () => {
// Publish API endpoints
server.publish('validateEmail', async (email) => {
// Returns JSON automatically
return {
valid: /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
};
});
server.start(52000);
});// client.js - calling the API
const response = await fetch('/api/validateEmail', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: 'test@example.com' })
});
const result = await response.json();The same control code runs on both server and client:
// client.js - defines the UI
const jsgui = require('jsgui3-html');
const Active_HTML_Document = jsgui.Active_HTML_Document;
class Demo_UI extends Active_HTML_Document {
constructor(spec = {}) {
super(spec);
const { context } = this;
// This code runs on BOTH server and client
// Use data binding to keep state synchronized
}
activate() {
// This code ONLY runs on the client
// Set up client-side event handlers here
}
}
module.exports = jsgui;// The binding system works seamlessly across server/client boundary
this.bind('count', model, {
toView: (value) => `Count: ${value}`,
toModel: (text) => parseInt(text) || 0
});
// On server: Renders initial value into HTML
// On client: Updates DOM when model changes| Aspect | Standalone Examples (examples/) |
Dev Examples (dev-examples/) |
|---|---|---|
| Dependencies | None (plain Node.js) | Requires jsgui3-server |
| Execution | node examples/binding_simple_counter.js |
node dev-examples/binding/counter/server.js |
| Purpose | Show binding system API | Show isomorphic patterns |
| Rendering | Client-side only | Server-side + client-side |
| File Structure | Single file | client.js + server.js |
| Browser Required | No | Yes |
| Real-world Pattern | API demonstration | Production-like setup |
- Start the server - Run the example's server script
- Open browser - Navigate to the displayed URL
- Make changes - Edit
client.jsfor UI changes - Restart server - Server rebuilds client bundle automatically
- Refresh browser - See your changes
const server = new Server({
Ctrl: Demo_UI, // Main UI control
src_path_client_js: 'path/to/client', // Client entry point
debug: true, // Include source maps
port: 52000, // Custom port (optional)
});The server can publish functions as HTTP endpoints:
server.on('ready', () => {
// Simple function - returns text/plain
server.publish('hello', () => 'Hello, World!');
// Complex function - returns application/json
server.publish('getData', () => {
return { users: ['Alice', 'Bob'], count: 2 };
});
// Async function
server.publish('fetchUser', async (userId) => {
const user = await database.getUser(userId);
return user;
});
server.start(52000);
});All published functions are available at /api/<name>.
Controls have two phases:
-
Constructor - Runs on both server and client
- Define UI structure
- Set up data binding
- Configure initial state
-
Activate - Runs only on client
- Attach event handlers
- Start animations
- Make API calls
class MyControl extends Active_HTML_Document {
constructor(spec = {}) {
super(spec);
// Runs on server AND client
}
activate() {
if (!this.__active) {
super.activate();
// Only runs on client
}
}
}CSS is automatically extracted from control definitions:
Demo_UI.css = `
.demo-ui {
padding: 20px;
background: #f5f5f5;
}
.counter-value {
font-size: 2em;
font-weight: bold;
}
`;The server includes this CSS in the served HTML automatically.
node --inspect dev-examples/binding/counter/server.jsUse browser DevTools. Enable source maps with debug: true in server config.
- Port already in use: Change the port number in
server.js - Module not found: Run
npm installfrom project root - Changes not reflected: Restart the server (it rebuilds on startup)
Each example follows this structure:
example-name/
├── client.js # UI control definition (runs on both server and client)
├── server.js # Server setup and API endpoints
└── README.md # Example-specific documentation
- Separate concerns: Keep server logic in
server.js, UI inclient.js - Use activation properly: Constructor for structure, activate for interaction
- Leverage binding: Let the binding system handle DOM updates
- Publish APIs: Use
server.publish()for backend functionality - Handle errors: Both server and client should handle errors gracefully
- Start with counter - Simplest example of server-side rendering
- Move to user-form - Adds server validation
- Explore data-grid - Shows data loading and client-side operations
- Study master-detail - Demonstrates navigation patterns
When adding new dev examples:
- Follow the client.js + server.js structure
- Include a README.md explaining the example
- Demonstrate a specific pattern or feature
- Keep examples focused and well-commented
- Test that server-side rendering works correctly
- For jsgui3-html questions: See main project README
- For jsgui3-server questions: See jsgui3-server repo
- For binding system questions: See DATA_BINDING.md