Sigment Guide
Introduction
Sigment is a lightweight reactive framework designed for developers who want speed, simplicity,
and full control of the DOM without virtual DOM and transpilers.
sigment support spa architeture you can read about spa here
sigment also support html-first architecture with ssr or mixed ssr and client in same page
sigment use the mpa (Multi-Part Application) you can read about it here
Installation
Install via npm:
npm install sigment
Or create a new project:
npx create-sigment-app my-app
📁 Project Structure
Sigment keeps your project clean and organized. Here’s the recommended structure:
// Root directory
/
├── src/
│ ├── assets/
│ │ └── css/
│ │ └── index.css
│ ├── components/
│ │ └── Hello.js
│ └── Main.js
├── index.html
├── jsconfig.json
├── vite.config.js
├── global.d.ts
├── package.json
🔹 src/ Directory
assets/— Contains static files like global CSS.components/— Reusable components go here.Main.js— Application entry point.
🔹 Root-Level Files
index.html— The main HTML page.jsconfig.json— Helps with module resolution and IntelliSense.vite.config.js— Vite config for development/build setup.global.d.ts— TypeScript declaration for global types like CSS modules.package.json— Project metadata and dependencies.
Example index.html
<!doctype html>
<html lang="en-US">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, minimum-scale=1.0">
<title>sigment start</title>
<link rel="stylesheet" href="/src/assets/css/index.css">
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/Main.js"></script>
</body>
</html>
🚀 Main Entry Point
Your application starts from Main.js / ts. It imports your components and mounts them into the DOM using Sigment’s MyApp and mount() API.
import { MyApp, mount } from "sigment";
import Hello from "./components/Hello";
MyApp.cleanHtml(true);
function Main() {
mount("root", Hello());
}
Main();
export default Main;
🔎 What’s Happening?
MyApp.cleanHtml(true)— remove the<properties>like id and other for clean html recommended to set true just in production.mount("root", Hello())— Renders theHellocomponent into therootdiv.- The
Main()function runs on startup and mounts the app.
🚀 Hello component
Example of Hello component.
export default function Hello() {
return div("Hello, world!");
}
Hello component— return html and render at the end at root.
Hello World
Create elements directly using tag functions:
document.body.appendChild(
div("Hello Sigment!")
);
Or
export default function App() {
return div("Hello, world!");
}
Main Entry
document.getElementById("root")?.appendChild(App());
Or
mount("root",App())
Mount
Sigment provides a simple way to connect your application to the DOM or initialize hydration using the mount function.
SPA Mode (Dynamic Injection)
Instead of manually manipulating the DOM with appendChild, you can use mount with a target ID and your root component:
// Option A: Passing the executed component
mount("root", App());
// Option B: Passing the component reference
mount("root", App);
HTML-First Mode (Hydration)
In an HTML-First architecture, where the structure is already present in the DOM (e.g., from the home page entry point), mount() is called without arguments to trigger the hydration engine.
MyApp.cleanHtml(true);
async function Main() {
// Global settings here
// Triggers hydration from the current entry point
mount();
}
Main();
Note: When mount() is empty, Sigment automatically connects logic to any data-component found in your existing HTML.
Nested Elements
You can nest elements directly by placing them as children inside a parent tag function like div, ul, etc.
Example – Nested Structure
function NestedExample() {
return div(
h2("Profile"),
p("User Info:"),
ul(
li("Name: Alice"),
li("Email: [email protected]")
)
);
}
The outer div acts as a container. All child elements are nested inside it, maintaining clean structure.
Reactive Signals
Use createSignal (Only for primitive variables or arrays) or just signal (For all types) to make reactive state:
const [count, setCount] = signal(0);
button({ onclick: () => setCount(count() + 1) }, "increment"),
p("counter is:",count)
Use an object-style signal with signal
const [state, setState] = signal({ counter: 0 });
button({ onclick: () => setState({ counter: state.counter + 1 }) }, "increment"),
p("counter from object is:", () => state.counter)
createEffect
createEffect tracks reactive dependencies and runs the provided function when they change. It's useful for side effects like logging, animations, or syncing state.
Why is this useful?
createEffect helps you respond to state changes without manually wiring up event listeners or re-computing values. It automatically re-runs when any reactive signal used inside changes.
import { signal, createEffect } from "sigment";
function Counter() {
const [count, setCount] = signal(0);
createEffect(() => {
console.log(`Count changed: ${count()}`);
});
return button({
onClick: () => setCount(count() + 1)
}, "Increment");
}
Every time you click the button, the signal count updates, triggering the effect and logging the new value.
Global Signals
Create global signals with createGlobalSignal or globalSignal.
create new file for example globalState.js or ts and add globalSignal like in the example below.
import { createGlobalSignal } from "sigment";
createGlobalSignal('userName', '');
createGlobalSignal('userMail', '');
export const GlobalKeys = {
userName: 'userName',
userMail: 'userMail'
};
To read global from any place in code you can do:
const [userName] = useGlobalSignal(GlobalKeys.userName);
To write global from any place in code you can do:
const [userName, setUserName] = getGlobalSignal(GlobalKeys.userName);
setUserName("some name");
Custom Tags
Dynamically define new tags with addSigment:
addSigment("card");
card("Content inside card");
// Renders: <s-card>Content inside card</s-card>
addSigment("myCard"); // before capital latter will add dash and the capital latter will convert to lower case
myCard("Custom element");
// Renders: <my-card>Custom element</my-card>
addSigment("card", "div");
card("Alias for div");
// Renders: <div>Alias for div</div>
Using with TypeScript
If you're using TypeScript, declare the types for your custom tags to enable type checking and IntelliSense.
It's best to put these declarations and registrations in a shared file like sigments.ts.
import { addSigment } from "sigment";
type Child = string | HTMLElement;
type Props<T extends keyof HTMLElementTagNameMap> =
Partial<HTMLElementTagNameMap[T]> & Record<string, any>;
declare global {
function signin(props: Props<"div">, ...children: Child[]): HTMLElement;
function signin(...children: Child[]): HTMLElement;
function sectionheader(props: Props<"section">, ...children: Child[]): HTMLElement;
function sectionheader(...children: Child[]): HTMLElement;
}
addSigment("signin");
addSigment("sectionheader");
export {};
Note: You can use addSigment() anywhere in your project, regardless of whether you're using TypeScript.
If you're using TypeScript, you only need to define the type declarations like shown above once—typically in a shared file like sigments.ts—but the addSigment() call itself can be used anywhere in your codebase.
3 Ways to Bind
Using a Local Signal:
function LocalExample() {
const [name, setName] = signal("");
return div(
div("type your name:",
input({ type: "text", onInput: (e) => setName(e.target.value) })
),
// First way: as a separate child function
div('Hi i am first way to bind', () => name()),
// Second way: inline in template string
div(() => `Hi i am second way to bind, ${name()}`),
// Third way: as variable
div('Hi i am third way to bind: ', name)
);
}
⚡ High-Performance Templates & Batching
Sigment v1.4.2 introduces a powerful batch utility. Instead of creating elements one-by-one, you define a Template and use the batch function to inject data efficiently.
1. Define a Template with "?"
The "?" symbol is a Dynamic Injection Point. Sigment pre-compiles these locations for lightning-fast updates.
// Example: A modern task list row template
const taskRowTmpl = createTemplate(li({ class: "task-item" },
span({ class: "task-id" }, "?"), // Placeholder 1
div({ class: "task-content" },
h4({ class: "task-title" }, "?"), // Placeholder 2
p({ class: "task-desc" }, "?") // Placeholder 3
)
));
2. Prepare the Container
The batch function needs a target element. You define this in your component's return statement using a standard Sigment element with a unique ID.
// In your component's return:
return div({ class: "results" },
ul({ id: "task-list" }) // This is where the magic happens
);
3. Execute the batch
The batch function maps your data to the template and injects it into the task-list container.
// Data: Array of arrays matching the "?" placeholders
const tasksData = [
["T-01", "Task Title", "Task Description"]
];
// batch(data, template, containerId, chunkSize, mode)
batch(tasksData, taskRowTmpl, "task-list", 1000, false);
🔍 How the mapping works
The "?" tells Sigment exactly where your data should go.
- Order: The first value in your data row fills the first
"?", the second fills the next, and so on. - Direct Update: Sigment remembers these exact paths, updating nodes directly without searching or diffing.
⚙️ Parameters Explained
| Parameter | Description |
|---|---|
data |
An array of arrays containing values for your placeholders. |
template |
The pre-compiled structure from createTemplate. |
containerId |
The ID of the DOM element (e.g., "task-list"). |
chunkSize |
The number of items to process in one frame (non-blocking). |
mode |
false replaces content. true appends to the end. |
🚀 Full Implementation Example
import { createTemplate, batch, mount } from "sigment";
// 1. Define the blueprint (Template)
const taskRowTmpl = createTemplate(li({ class: "task-item" },
span({ class: "task-id" }, "?"),
div({ class: "task-content" },
h4({ class: "task-title" }, "?"),
p({ class: "task-desc" }, "?")
)
));
// 2. Create the Component
function TaskManager() {
const loadData = () => {
// Generate 5,000 tasks on the fly
const bigData = Array.from({ length: 5000 }, (_, i) => [
`ID-${i}`,
`Feature Request #${i}`,
"Optimized DOM update using Sigment batch engine."
]);
// Inject data into the "task-list" container
batch(bigData, taskRowTmpl, "task-list", 1000, false);
};
return div({ class: "container" },
div({ class: "header" },
h2("Sigment Task Engine"),
button({ onclick: loadData, class: "btn-main" }, "Render 5,000 Tasks")
),
div({ class: "results" },
ul({ id: "task-list" }) // Target container
)
);
}
// 3. Mount to DOM
mount("root", TaskManager());
ul container from the data injection, Sigment allows the initial page load to be extremely light, deferring the heavy lifting of rendering thousands of items to the batch engine.
🛠️ Template Helpers & Surgical Updates
Sigment treats your rendered batches as a Live Virtual Tree. Unlike standard DOM manipulation, these helpers allow you to update data and move elements with zero overhead.
swap or destroy an item, the positions (indexes) of other items will shift, just like in a JavaScript Array.
Full Implementation Example
import { createTemplate, batch, mount, gve } from "sigment";
// 1. Define the blueprint
const taskRowTmpl = createTemplate(li({ class: "task-item" },
span({ class: "task-id" }, "?"), // Index 0
div({ class: "task-content" },
h4({ class: "task-title" }, "?"), // Index 1
p({ class: "task-desc" }, "?") // Index 2
)
));
function TaskManager() {
const loadData = () => {
const bigData = Array.from({ length: 5000 }, (_, i) => [
`ID-${i}`, `Task #${i}`, "Batch processed."
]);
batch(bigData, taskRowTmpl, "task-list", 1000);
};
// Memory-efficient clearing of the entire list
const clearAll = () => {
gve("task-list").clear();
};
const promoteTask = () => {
const list = gve("task-list");
const target = list.get(4);
if (target) {
target.updateVal(1, "⭐ PROMOTED");
target.swapWith(0);
}
};
return div({ class: "container" },
div({ class: "controls" },
button({ onclick: loadData }, "Render 5,000 Tasks"),
button({ onclick: promoteTask }, "Promote Row #5"),
button({ onclick: clearAll, class: "warning" }, "Clear List")
),
ul({ id: "task-list" })
);
}
mount("root", TaskManager());
API Quick Reference
| Method | Description |
|---|---|
.get(index) |
Retrieves the virtual node at the current position (0-based). |
.swapWith(idx) |
Moves the element to the target index. Note: Indexes of other items will shift. |
.updateVal(idx, val) |
Replaces the content of the "?" placeholder at idx. |
.addVal(idx, val) |
Appends a string to the current value of the placeholder at idx. |
.clear() |
Wipes all children from the element and releases references from memory. Highly optimized. |
.destroy() |
Removes the element and unregisters it from memory. |
💡 Pro Tip: Why use clear()?
Using gve("container").clear() is significantly faster than removing elements one-by-one.
It leverages textContent = "" while simultaneously emptying Sigment's internal maps,
making it the gold standard for performance-heavy applications.
Fragment
Fragment(...children) allows you to group multiple elements without introducing an actual DOM wrapper.
Example – Without Fragment
function Card() {
return div(
h2("Title"),
p("Some text")
);
}
Renders:
<div>
<h2>Title</h2>
<p>Some text</p>
</div>
Example – With Fragment
function Card() {
return fragment(
h2("Title"),
p("Some text")
);
}
Renders:
<h2>Title</h2>
<p>Some text</p>
Why is this useful?
- No extra DOM nodes – keeps your HTML clean
- Better performance – fewer elements mean less memory and faster rendering
- Zero styling impact – no unexpected box models or spacing from wrappers
- Logical grouping – lets you group elements structurally in code
Note: Fragments render their children in O(1) time without creating an additional DOM node themselves. Only the children appear in the final DOM.
Global Configuration (MyApp)
The MyApp object is the central entry point for configuring global framework behavior. These settings should be applied in your main entry file (e.g., Main.js) before calling mount().
Example Setup
// Global configuration in Main.js
MyApp.cleanHtml(true);
MyApp.setStopPropagation(true);
MyApp.setMaxCacheSize(50);
// Define the global routes
MyApp.setRoute(Routes);
// Initialize the app (Target ID first, then Component Execution)
mount("root", App());
Available Methods
- MyApp.cleanHtml(boolean) – When
true, Sigment removes all internal reactive tracking attributes and IDs from the DOM, resulting in pristine HTML for production environments. - MyApp.setRoute(RoutesObject) – Registers the global routing configuration, enabling
NavigateToand async route guards. - MyApp.setloadAtRunTime(boolean | Object) – Controls how components are hydrated. If an object is provided, it acts as a mapping for runtime component injection.
- MyApp.setStopPropagation(boolean) – When enabled, it prevents event bubbling across all framework-managed elements by default.
- MyApp.setMaxCacheSize(number) – Sets the limit for how many pages and stateful components are kept in the background memory cache to optimize memory usage.
Mounting the App
The mount function requires the ID of the target container and the executed root component:
mount("target-id", RootComponent());
Why is this important?
- Performance – Fine-tune memory usage with cache limits and optimized hydration.
- SEO & Cleanliness – Use
cleanHtmlto make your production source code look like hand-written HTML. - Predictability – Global event control via
setStopPropagationprevents common UI bugs and unexpected side effects.
Note: MyApp settings are static and global. They must be defined before calling mount() to ensure the entire application instance follows the specified rules.
🎨 Styling in Sigment: Global CSS vs. CSS Modules
Sigment supports both global CSS files and scoped CSS modules — giving you flexibility in how you style your components.
✅ 1. Importing Global CSS
import './hello.css';
- Effect: All class names defined in
hello.cssare available globally across the app. - Usage: Just pass the class name as a string in the
classattribute.
Example (hello.css):
.hi {
font-size: 20px;
color: darkblue;
}
In component:
p({ class: "hi" }, 'Hello from Sigment')
🎯 2. Using CSS Modules
import styles from './hello.module.css';
- Effect: Class names are automatically scoped (e.g.,
fnt600__hello__abc123). - Usage: Access them as properties:
styles.className.
Example (hello.module.css):
.fnt600 {
font-weight: 600;
}
In component:
p({ class: styles.fnt600 }, 'Bold text')
🧪 3. Combining Global and Module Styles
p({ class: "hi " + styles.fnt600 }, 'Mixed styles')
"hi"→ from global CSSstyles.fnt600→ scoped class from CSS Module
💡 Final Example
import './hello.css'; // Global styles
import styles from './hello.module.css'; // Scoped module styles
function Hello() {
return div(
p({ class: "hi " + styles.fnt600 },
'Hello from Sigment,',
br(),
'Inspect this element,',
br(),
'and see how styles apply'
)
);
}
📦 Summary for Developers
| Feature | Global CSS | CSS Modules |
|---|---|---|
| File name | hello.css |
hello.module.css |
| Import syntax | import './file.css' |
import styles from |
| Class use | "hi" |
styles.hi |
| Scope | Global (shared) | Local (scoped) |
| Collision safe | ❌ No | ✅ Yes |
🔧 Tips
- Use global CSS for layout, resets, or base styles.
- Use CSS modules for component-specific styling.
- Always combine multiple classes with a string or helper function (e.g.,
"a " + styles.borclsx()).
Lifecycle Helpers
Lifecycle utilities like createEffect, onPaint, and paintFinish allow you to run logic at different stages of a component's rendering flow.
These helpers are entirely optional, and you can choose to use them only when needed.
Lifecycle Flow
createEffect(fn)— runs whenever signals insidefnchange.onPaint(fn)— schedulesfnto run after the next paint cycle.paintFinish(fn)— runsfnonly once, after the first paint is complete.
Example – lifecycle demo
import { signal, onPaint, paintFinish, createEffect } from "sigment";
function MyComponent() {
const [count, setCount] = signal(0);
createEffect(() => {
console.log(`Count changed: ${count()}`);
});
onPaint(() => {
console.log("Runs after every browser paint.");
});
paintFinish(() => {
console.log("Runs only once, after the first paint.");
});
return div(
button({ onClick: () => setCount(count() + 1) }, () => `Clicked ${count()} times`)
);
}
This demonstrates how createEffect, onPaint, and paintFinish can be used together to manage logic around reactive updates and browser paint timing.
Routing
Sigment supports defining routes as a map of route names to route configurations. Each route can have:
loader: a function that dynamically imports the component for that route.urlParam: a string pattern like'{id}/{pageid}'to extract URL parameters.guard: an optional function returningbooleanorPromise<boolean>to control access.logic: optional function to run extra logic when loading the route.cacheExpiration: optional time in ms to cache the loaded component.
You can also specify a fallback route which loads if no matching route is found.
Example (TypeScript)
import type { RoutesMap } from 'sigment';
export const Routes: RoutesMap = {
about: {
loader: () => import('./About'),
guard: () => true,
},
user: {
loader: () => import('./User'),
path: '/user/:id?/:pageid?',
//or you can do - urlParam:'{id}/{pageid}'
guard: async (params) => {
return await checkPermission(params?.id);
}
},
dash: {
loader: () => import('./Dash'),
cacheExpiration: 60000,
guard: () => checkPermission('dashboard'),
},
fallback: 'login'
};
Usage
Use parsePath() to get the current route and params, then loadRunFunc() to load the component:
const container = div({class:"body"},'Loading...');
const { componentName, params } = parsePath(Routes);
const content = await loadRunFunc(Routes, componentName, params);
container.replaceChildren(content);
URL Parameters
When using urlParam with a pattern like '{id}/{pageid}', or When using path with a pattern like '/user/:id?/:pageid?' the URL segments after the route name are parsed into an object.
For example, the URL /user/123/45 will set params = { id: '123', pageid: '45' } which is passed to your component and guard.
Route Guards
Guards allow you to check permissions or conditions before loading a route. They can be async and should return true or false.
memoizeFunc
Caches the result of a function based on its arguments. Useful for preventing unnecessary recomputation or repeated fetch calls.
Signature:
(alias) function memoizeFunc<F extends (...args: any[]) => any>(
fn: F,
ttl?: number,
options?: MemoizeOptions
): F & {
clear(): void;
}
Import:
import { memoizeFunc } from "sigment";
Example – Memoize a computation:
const heavyCalc = memoizeFunc((n) => {
console.log("Calculating...");
return n * 10;
});
console.log(heavyCalc(5)); // logs: Calculating... → 50
console.log(heavyCalc(5)); // cached → 50
Example – With TTL (time to live):
const fetchData = memoizeFunc(fetchDataFromAPI, 5000); // cache lasts 5 seconds
To manually clear cache:
fetchData.clear();
fetchCache
A convenient wrapper around fetch with automatic caching. Results are stored in memory and reused until the TTL (time to live) expires.
Signature:
(alias) function fetchCache<T = any>(
url: string,
ttl?: number,
options?: RequestInit
): Promise<T>
Import:
import { fetchCache } from "sigment";
Example – Basic Usage:
const data = await fetchCache("https://api.example.com/posts");
Example – With TTL (cache expiration in ms):
const data = await fetchCache("https://api.example.com/posts", 10000);
// Result is cached for 10 seconds
Example – With fetch options:
const result = await fetchCache("https://api.example.com/user", 5000, {
headers: {
Authorization: "Bearer token"
}
});
getVirtualElementById (gve)
getVirtualElementById(id) (alias gve(id)) retrieves a reference to a virtual element.
It accepts either a string (ID) or a direct HTML Element.
Useful for interacting with specific elements in your reactive UI without querying the real DOM directly.
Signature
function getVirtualElementById(id: string | HTMLElement): HTMLElement & SigmentExtensions;
function gve(id: string | HTMLElement): HTMLElement & SigmentExtensions;
Example 1 – Standard Component Usage
Use paintFinish to ensure the element is available in the virtual tree before applying manual styles or event listeners.
import { signal, getVirtualElementById, paintFinish, createEffect, mount } from "sigment";
function Counter() {
const [count, setCount] = signal(0);
createEffect(() => {
console.log(`Current count: ${count()}`);
});
paintFinish(() => {
console.log("Function that runs only once, after the first paint");
// Shorthand: gve("counter")
const counterEl = getVirtualElementById("counter");
if (counterEl) {
counterEl.style.backgroundColor = "yellow";
// Add direct event listener via the virtual reference
counterEl.addEventListener("click", () => alert(`You clicked: ${count()}`));
}
});
return div(
button({ : () => setCount(count() + 1) }, () => `increment me, ${count()}`),
div({ : "counter" }, () => `counter is, ${count()}`)
);
}
mount("root", Counter());
🚀 Advanced Template Extensions
When gve targets an element created via batch or createTemplate, it unlocks a set of high-performance methods for surgical DOM manipulation:
| Method | Description |
|---|---|
.get(index) |
Retrieves a virtual child by index (0-based). gve("tbody").get(1) targets the second child. |
.swapWith(index) |
Swaps the position of the current element with another element at the target index within the same parent. |
.updateVal(idx, val) |
Overwrites the value of the dynamic placeholder ("?") at the specific index. |
.addVal(idx, val) |
Appends a string to the current value of the placeholder at the specific index. |
.clear() |
Memory King: Clears all children and wipes their virtual references. Essential for performance in large-scale apps. |
.destroy() |
Removes the element from the DOM and wipes it from Sigment's virtual memory to prevent leaks. |
Example 2 – Full Template Manipulation
This example demonstrates how to surgically manage a large list: reorganizing items, updating values, and resetting the container.
const list = gve("task-list");
if (list) {
// 1. Access children by index
const firstItem = list.get(0);
const secondItem = list.get(1);
// 2. Swap positions: Move the 2nd item to the 11th position
secondItem.swapWith(10);
// 3. Update data values
firstItem.updateVal(0, "New Title for Item 1");
// 4. Destroy a single item surgically
list.get(5).destroy();
// 5. RESET: Clear everything and free memory instantly
// This is what achieved the 1.08 "Clear" score in benchmarks!
list.clear();
console.log("Memory cleaned and UI reset at lightning speed.");
}
Sigment is engineered for extreme memory efficiency. The clear() method explicitly unlinks internal virtual references, reducing memory overhead by up to 30% compared to standard reactive patterns. This ensures a near-zero memory footprint even in data-intensive applications with rapid update cycles.
📦 Component Overriding with Stateful or Stateless
Sigment supports replacing components dynamically using gvec() with control over state and optional lifecycle triggers. This allows:
- ✅ Defining components with static functions (e.g.,
Dashboard.writeToLog()) - ✅ Dynamically loading and overriding other components at runtime
- ✅ Preserving or resetting component state (via the
trueorfalsesecond argument) - ✅ Sending parameters or triggering target methods after override
🤠 Concept
gvec({
"login": Login,
"dash": await loadFunc(runtime, "dash"),
"param": [7, "pp"]
}, true, {
writeToLog: ["Login component"]
});
Navigate("dash");
🔐 Login Component Example
import { Navigate, getGlobalSignal, loadFunc, gvec, addSigment } from "sigment";
import { GlobalKeys } from "./global/globalState.js";
import loadAtRunTimeComponents from "./utils/loadAtRunTimeComponents.js";
import Dashboard from "./Dashboard.js";
function Login(): HTMLElement {
const [userName, setUserName] = getGlobalSignal(GlobalKeys.userName);
addSigment("signin");
async function loadDashboard() {
gvec({
"login": Login,
"dash": await loadFunc(loadAtRunTimeComponents, "dash"),
"param": [7, "pp"]
}, true, {
writeToLog: ["Login component"]
});
Navigate("dash");
}
return signin({ id: "login" },
div(
div("user name:",
input({
type: "text",
onInput: (e: InputEvent) =>
setUserName((e.target as HTMLInputElement).value)
})
),
div("password:",
input({ type: "password" })
),
div({ class: "username" }, 'User name is: ', () => userName()),
button({ onclick: () => loadDashboard() }, "to dash")
)
);
}
export default Login;
📊 Dashboard Component Example
import { useGlobalSignal, createSignal, div, input, h2, button } from "sigment";
import { GlobalKeys } from "./global/globalState.js";
import loadAtRunTimeComponents from "./utils/loadAtRunTimeComponents.js";
import { Navigate, gvec, loadFunc } from "sigment";
import Login from "./Login.js";
interface DashType {
(props: any): HTMLElement;
writeToLog: (from: any) => void;
}
function Dashboard(props: any): HTMLElement {
const [userName] = useGlobalSignal(GlobalKeys.userName);
const [name, setName] = createSignal("");
(Dashboard as DashType).writeToLog = function (from: any): void {
console.log("writeToLog is fired from", from);
};
const handleClick = async () => {
gvec({
"dash": Dashboard,
"login": await loadFunc(loadAtRunTimeComponents, "Login")
}, false);
Navigate("/");
};
return div({ id: "dash" },
h2(() => `Welcome, ${userName()}!`),
div("Change your name:"),
input({
type: "text",
value: name(),
onInput: (e: InputEvent) =>
setName((e.target as HTMLInputElement).value)
}),
div(() => `Local name is: ${name()}`),
button({ onclick: handleClick }, "to login")
);
}
export default Dashboard;
📂 Runtime Loader
const loadAtRunTimeComponents = {
"login": () => import("../Login.js"),
"dash": () => import("../Dash.js")
};
export default loadAtRunTimeComponents;
rpc – Call Static Component Methods Remotely
The rpc function allows you to dynamically call static methods attached to a component,
such as Dashboard.writeToLog, from outside the component context.
This is useful for triggering logic or returning values from components programmatically.
Signature
function rpc(
component,
methods: Record<string, any[]>
): Record<string, any>;
Example 1 – call a void method
function Dashboard(props) {
// component internals
}
Dashboard.writeToLog = function(from) {
console.log("writeToLog is fired type is void", from);
};
rpc(Dashboard, {
writeToLog: ["some text"]
});
This will run Dashboard.writeToLog("some text").
📦 You can call this from another component like this dont forget to import Dashboard
rpc(Dashboard, {
writeToLog: ["called from HomePage"]
});
Example 2 – call multiple methods with return values
Dashboard.writeToLogWithValue = function(val) {
console.log("return value", val);
return val;
};
const res = rpc(Dashboard, {
writeToLog: ["some text"],
writeToLogWithValue: ["i am with value"]
});
console.log(res);
Methods that return values will be included in the result. Methods returning
undefined (like writeToLog) will appear with undefined
in the response.
Note: Static methods like Dashboard.writeToLog must be defined outside the component’s render body. This ensures they’re available at any time and do not depend on component mounting.