All framework symbols are importable from the CDN or local simplijs.js.
// Full type definition (simplijs.d.ts)
// Register a new SimpliJS component
component(name: string, setup: ComponentSetup): void;
type ComponentSetup = (element: HTMLElement, props: Record) => ComponentOutput;
type ComponentOutput = {
render?: () => string;
onMount?: () => void;
onUpdate?: () => void;
onDestroy?: () => void;
[key: string]: any; // Custom methods
};
component(name, setup)Registers a custom element. The setup function receives the element instance and a reactive props object (auto‑synced from attributes).
// Example with typed props & methods
component('user-profile', (el, props) => {
const state = reactive({ count: 0 });
return {
inc: () => state.count++,
render: () => `
Count: ${state.count} | Initial: ${props.initialCount}
`
};
});
⚠️ Attribute sync: Attributes like count="5" become props.count (string). Use watch or computed for number coercion.
reactive(), computed(), watch()// deeply reactive with error handling
const form = reactive({
email: '',
touches: 0
});
// computed with implicit error catching → component.onError can handle
const isEmail = computed(() => {
if (!form.email.includes('@')) throw new Error('Invalid email format');
return true;
});
watch(() => form.email, (newVal, oldVal) => {
try {
console.log(`email changed: ${oldVal} → ${newVal}`);
} catch (e) {
// if watch throws, it bubbles to component onError (if defined)
throw e;
}
});
computed or watch will be caught by the nearest component’s onError hook. Unhandled errors are logged to console but do not break the app.
ref() & lifecycle hooksRefs are populated after render, before onMount.
component('focus-input', (el) => {
return {
onMount: () => {
const input = el.querySelector('input');
input?.focus();
},
onUpdate: () => console.log('rerendered'),
onDestroy: () => console.log('cleanup'),
render: () => ``
};
});
Ref assignment: use ref="yourRefName" in template string, matching the key returned from ref().
emit() & on() (global bus)// component A: emit
component('pinger', () => ({
ping: () => emit('network:status', { online: navigator.onLine }),
render: () => ``
}));
// component B: listen (auto clean on destroy)
component('ponger', () => {
const unsub = on('network:status', (data) => {
console.log('pong', data);
});
Error handling: if a handler throws, other listeners still run; error is emitted to window.onerror and component.onError of the listener’s component (if any).
SimpliJS provides 8 native directives that work directly in your HTML. No compilation required. Below is the categorized reference.
| Category | Directives | Description / Syntax |
|---|---|---|
| Core | s-app | Application boundary for the engine. Initialized on mount. |
| Binding | s-bind / s-model | Deep reactive text/number/form sync. |
| Logic | s-if / s-for / s-switch | Template-driven logic flow with optimized DOM patching. |
| Events | s-click / s-submit / s-key | Declarative performance-optimized event listeners. |
| Utility | s-text / s-html / s-ref | Direct content and DOM ref management. |
Note: The v3.2.0 Directive Engine is highly optimized for performance and works directly on the DOM without a Virtual DOM overhead.
createApp().form() – automated validationinterface FormConfig {
fields: string[]; // field names
validate?: Record<string, (val: any) => string | null>;
onError?: (errors: Record<string, string>) => void;
submit: (data: Record<string, any>) => void;
}
component('contact-form', () => {
const handler = createApp().form({
fields: ['name', 'email'],
validate: {
email: (v) => /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(v) ? null : 'invalid email',
name: (v) => v.trim() ? null : 'name required'
},
onError: (errs) => console.table(errs),
submit: (data) => fetch('/api', { method:'POST', body: JSON.stringify(data) })
});
return {
handler,
render: () => `
`
};
});
✋ Invalid fields automatically get class .is-invalid; the onError receives map of field → message.
use – universal component bridgeimport { use, component } from 'simplijs';
// import a React icon component (ESM)
const IconTag = use.react('https://esm.sh/lucide-react?alias=react&bundle', 'Heart');
component('like-button', () => ({
render: () => `
<button>
<${IconTag} color="red" size="20"></${IconTag}>
like
</button>
`
}));
// error handling: if module fails, component renders nothing and onError is called
Status: The Bridge is fully operational in v3.2.0, allowing seamless integration of React, Vue, and Svelte components into SimpliJS layouts.
The SimpliJS ecosystem includes 7 high-performance plugins for enterprise features.
Complete auth lifecycle management.
auth.login(creds) - Authenticate and store session.auth.user - Reactive user object.auth.guard(route) - Route protection helper.Declarative SPA routing.
router.push(path) - Navigation.router.params - Reactive URL parameters.<s-view> - Router outlet directive.Extended state time-travel and persistence.
s.vault.sync() - Sync state with remote server.s.vault.encrypt() - AES encryption for sensitive local state.Also includes: @simplijs/bridge-adapters, @simplijs/devtools, @simplijs/forms, and @simplijs/ssg.
Documentation for @simplijs/ssg and built-in industrial SEO tools.
// Dynamic Metadata Updates
setSEO({
title: 'My Profile | SimpliJS',
description: 'Pro-grade Reactive Social App',
image: 'https://cdn.com/og.jpg',
twitterHandle: '@sb_tech'
});
// Structured Data (JSON-LD)
setJsonLd({
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "SimpliJS"
});
// Breadcrumbs & Theme
setBreadcrumbs([{ name: 'Docs', url: '/docs' }, { name: 'SEO', url: '/seo' }]);
setThemeColor('#6a0dad');
export default {
baseUrl: 'https://mysite.com',
outDir: 'dist',
minify: true,
rss: { title: 'Blog', items: [...] },
routes: {
'/': HomeTemplate,
'/blog': BlogListTemplate
}
};
// CLI Execution: node ssg.js ssg.config.js
SimpliJS addresses traditional framework security vulnerabilities (XSS, Template Injection) at the architectural level.
By default, s-state and s-click expressions are evaluated through a high-performance sandbox that prevents access to window, document, or sensitive cookies.
SimpliJS is fully compliant with strict Content Security Policies. It avoids eval() and new Function() for directive parsing, using a custom-built lexical tokenizer.
reactive.vault() – time travel stateinterface VaultControls {
back(): void; // undo
forward(): void; // redo
share(): string; // returns URL with ?simpli-debug=base64
timeline(): ReadonlyArray<T> // debug history
}
const globalState = reactive.vault({
filter: 'all',
items: []
});
component('vault-ui', () => ({
undo: () => globalState.vault.back(),
redo: () => globalState.vault.forward(),
shareDebug: () => {
const url = globalState.vault.share();
navigator.clipboard?.writeText(url);
},
render: () => `
<div>
<button onclick="globalState.vault.back()">↩️ undo</button>
<button onclick="globalState.vault.forward()">↪️ redo</button>
<button onclick="alert(globalState.vault.share())">🔗 share timeline</button>
</div>
`
}));
⏳ Restore from URL: SimpliJS automatically detects ?simpli-debug=... on page load and hydrates the vault.
Props are reactive, but note that HTML attributes are always strings. Use computed / watch to convert.
component<{ value: string; }>('numeric-display', (el, props) => {
const asNumber = computed(() => {
const num = Number(props.value);
if (isNaN(num)) throw new TypeError(`"${props.value}" is not a number`);
return num;
});
return {
render: () => `<p>${asNumber.value} * 2 = ${asNumber.value * 2}</p>`,
onError: (err) => {
el.innerHTML = `⚠️ ${err.message}`; // fallback ui
}
};
});
SimpliJS does not swallow errors – it delegates to hooks and provides fallbacks.
| Scenario | Error object | Handled by |
|---|---|---|
| render() throws | RenderError | console.log + engine fallback |
| event handler throws | original error | window.onerror |
| watch / computed throws | original | console.log + re-throws |
| form validation error (custom) | n/a | config.onError / UI classes |
| bridge import fails | ImportError | console.log |
// top‑level error boundary pattern (wrapping component)
component('error-boundary', () => {
const state = reactive({ hasError: false, errorMsg: '' });
return {
onError: (err) => {
state.hasError = true;
state.errorMsg = err.message;
},
render: () => state.hasError
? `<div>🔥 crash: ${state.errorMsg}</div>`
: `<inner-component />` // child may throw
};
});
SimpliJS v3.2.0 supports full content projection via s-slot and default slots.
component('user-layout', () => ({
render: () => `
<header><s-slot name="header" /></header>
<main><s-slot /></main>
`
}));
/**
* @param {HTMLElement} el
*/
function setup(el) {
return {
render: () => `Component is active`
};
}
component('typed-demo', setup);
Use the included simplijs.d.ts for full IDE autocompletion.