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.
Installation
Install via npm:
npm install sigment
Or create a new project:
npx create-sigment-app my-app
Hello World
Create elements directly using tag functions:
document.body.appendChild(
div("Hello Sigment!")
);
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
or just signal
to make reactive state:
const [count, setCount] = signal(0);
button({ onclick: () => setCount(count() + 1) }, count)
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 from any place in code:
const [userName] = useGlobalSignal(GlobalKeys.userName);
To write from any place in code:
const [userName, setUserName] = getGlobalSignal(GlobalKeys.userName);
setUserName("some name");
Custom Tags
Dynamically define new tags with addsigment
:
addsigment("card");
card("Content inside card")
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: interpolated placeholder
div(`Hi i am third way to bind: {{name}}`)
);
}
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.
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 returningboolean
orPromise<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'),
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 { 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}'
, 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"
}
});