core.js Documentation
A lightweight, dependency-free JavaScript framework for building dynamic, data-driven web interfaces using simple HTML attributes.
Key Features
- ✅ Zero Dependencies - Pure vanilla JavaScript
- ✅ Async-Native - Built on modern async/await patterns
- ✅ Pocket-Based - Component architecture without virtual DOM
- ✅ Template Engine - Powerful data binding with
{{rec:field}}syntax - ✅ Smart Routing - SPA navigation with clean URLs
- ✅ Flexible Storage - DOM, Data Attributes, or Session Storage
- ✅ Built-in Validation - Comprehensive scrubbing and formatting
Installation
CDN (Recommended)
<!-- Latest version -->
<script src="https://cdn.jsdelivr.net/gh/Sitezip/core.sbs/core.js"></script>
<!-- Specific version (recommended for production) -->
<script src="https://cdn.jsdelivr.net/gh/Sitezip/core.sbs@20260125.1/core.js"></script>
Self-Hosted
<script src="/path/to/core.js"></script>
Quick Start
1. Create a Template
Templates are defined in a hidden section with id="cr-data":
<section id="cr-data" style="display:none;">
<template name="users">
<div class="core-clone" data-core-data="users">
<h3>{{rec:name}}</h3>
<p>{{rec:email}}</p>
<p>Balance: {{rec:balance:money:$}}</p>
</div>
</template>
</section>
2. Create a Pocket
Pockets are containers where templates are rendered:
<div class="core-pocket"
data-core-templates="users"
data-users-core-source="https://api.example.com/users">
</div>
3. Initialize
core.js initializes automatically on DOMContentLoaded, but you can also call it manually:
core.init();
Architecture Overview
core.js follows a lifecycle-driven approach with distinct phases:
Rendering Lifecycle
- SOC (Start of Call) - Initialization begins
- getTemplate() - Fetch missing templates
- addTemplate() - Inject templates into pockets
- getData() - Fetch missing data
- addData() - Clone and populate with data
- EOL (End of Lifecycle) - Hydration, formatting, cleanup
Core Modules
| Module | Purpose |
|---|---|
core.be |
Backend operations (fetch, cache) |
core.cr |
Registry (data/template storage) |
core.pk |
Pocket lifecycle management |
core.hf |
Helper functions (date, sorting, etc.) |
core.sv |
Validation and scrubbing |
core.ux |
User experience utilities |
core.ud |
User-defined hooks and settings |
Pockets
Pockets are container elements that act as dynamic insertion points for components.
Basic Pocket
<div class="core-pocket" data-core-templates="myTemplate"></div>
Pocket with Data Source
<div class="core-pocket"
data-core-templates="products"
data-products-core-source="/api/products">
</div>
Multiple Templates
<div class="core-pocket"
data-core-templates="header,content,footer">
</div>
Templates
Templates use double curly brace syntax for data binding.
Template Syntax
{{type:source:reference:format:clue}}
Template Types
| Type | Description | Example |
|---|---|---|
rec or # |
Current record data | {{rec:name}} |
data or @ |
Global registry data | {{data:config:apiKey}} |
aug or ! |
Augmented metadata | {{aug:index}} |
Complete Example
<template name="userCard">
<div class="core-clone" data-core-data="users">
<h3>{{rec:name}}</h3>
<p>{{rec:address.city}}</p>
<p>{{rec:email:lower}}</p>
<p>{{rec:balance:money:$}}</p>
<span>Item {{aug:count}}</span>
<img {{rec:avatar:core_pk_attr:src}} alt="Avatar">
</div>
</template>
Data Binding
Clone Elements
Elements with core-clone class are duplicated for each record:
<div class="core-clone" data-core-data="products">
<h3>{{rec:name}}</h3>
<p>{{rec:price:money:$}}</p>
</div>
Nested Data Access
{{rec:user.profile.name}}
{{rec:address.billing.street}}
{{rec:settings.theme.colors.0}}
{{rec:tags.[n]}}
Lifecycle
core.init()
└─> core.cr.init()
└─> core.pk.init()
└─> core.pk.soc()
├─> core.be.awaitAll()
├─> core.ud.soc()
├─> core.pk.getTemplate()
├─> core.pk.addTemplate()
├─> core.pk.getData()
├─> core.pk.addData()
└─> core.pk.pk_eol()
├─> core.hf.hydrateByClass()
├─> core.hf.formatByClass()
└─> core.ud.pk_eol()
Routing
Enable Routing
core.ud.init = () => {
core.useRouting = true;
};
Pretty Path Format
<a href="#/_main/home">Home</a>
<a href="#/_main/dashboard/_sidebar/menu">Dashboard</a>
<a href="#/_main/profile:https%3A%2F%2Fapi.com%2Fuser%2F123">Profile</a>
Programmatic Navigation
core.hf.setRoute('#/_main/about');
const currentRoute = core.hf.getRoute();
core.init()
Method
Initializes the core.js framework. Called automatically on DOMContentLoaded.
core.init();
core.be - Backend
core.be.getData()
Async Method
Fetches JSON data from a source and stores it in the registry.
| Parameter | Type | Description |
|---|---|---|
dataRef |
string | Unique identifier |
dataSrc |
string | URL to fetch from |
settings |
object | Optional config |
await core.be.getData('users', '/api/users');
await core.be.getData('users', '/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: { filter: 'active' }
});
core.be.getTemplate()
Async Method
await core.be.getTemplate('header', '/templates/header.html');
core.be.awaitAll()
Async Method
Waits for all active backend requests to complete.
core.be.getData('users', '/api/users');
core.be.getData('products', '/api/products');
await core.be.awaitAll();
Cache Configuration
core.be.cacheExpireDefault = 3600;
core.be.cacheExpire = {
type: 'data',
name: 'users',
seconds: 300
};
core.cr - Registry
Storage Tiers
| ID | Type | Description |
|---|---|---|
0 |
DOM | Memory-only |
1 |
Static | data-* attributes (default) |
2 |
Session | sessionStorage |
core.cr.setData() / getData()
core.cr.setData('users', usersArray);
core.cr.setData('token', 'abc123', null, 2);
const users = core.cr.getData('users');
const token = core.cr.getData('token', null, 2);
core.cr.setTemplate() / getTemplate()
core.cr.setTemplate('myTemplate', '<div>{{rec:name}}</div>');
const template = core.cr.getTemplate('myTemplate');
core.pk - Pockets
core.pk.soc()
Async Method
Start of Call - initiates the rendering lifecycle.
await core.pk.soc();
core.pk.cloner()
Clones a template for each record in an array.
const records = [
{ name: 'John', age: 30 },
{ name: 'Jane', age: 25 }
];
const template = '<div>{{rec:name}} is {{rec:age}}</div>';
const html = core.pk.cloner(records, template);
core.hf - Helper Functions
core.hf.date()
Robust date formatting with custom tokens.
| Token | Output |
|---|---|
YYYY |
4-digit year |
MM |
Month (01-12) |
DD |
Day (01-31) |
HH |
Hour (00-23) |
:MM |
:Minutes |
P |
AM/PM |
core.hf.date();
core.hf.date(null, 'YYYY-MM-DD');
core.hf.date(1738627200, 'M/D/YY H:MM P');
core.hf.digData()
Deep-seek values in nested objects.
const user = {
name: 'John',
address: { billing: { street: '123 Main' } },
tags: ['admin', 'user']
};
core.hf.digData(user, 'name');
core.hf.digData(user, 'address.billing.street');
core.hf.digData(user, 'tags.0');
core.hf.digData(user, 'tags.[n]');
core.hf.sortObj()
const users = [
{ name: 'Charlie', age: 30 },
{ name: 'Alice', age: 25 }
];
core.hf.sortObj(users, 'name');
core.hf.sortObj(users, 'age', 'numeric', 'DESC');
core.hf.uuid()
const id = core.hf.uuid();
const prefixed = core.hf.uuid('user-');
core.hf.hydrateByClass()
<span class="h-users-name"></span>
<span class="h-users-email"></span>
<script>
core.hf.hydrateByClass();
</script>
core.hf.formatByClass()
<span class="f-money" data-f-clue="$">1234.56</span>
<span class="f-upper">hello</span>
core.sv - Validation
core.sv.scrub()
Validates and transforms an array of input objects.
| Scrub | Description |
|---|---|
req |
Required field |
email |
Valid email |
url |
Valid URL |
num |
Numeric value |
min:n |
Minimum length |
max:n |
Maximum length |
match:field |
Match another field |
const result = core.sv.scrub([
{ name: 'email', value: 'user@example.com', scrubs: ['req', 'email'] },
{ name: 'password', value: 'secret123', scrubs: ['req', 'min:8'] },
{ name: 'age', value: '25', scrubs: ['req', 'num', 'gte:18'] }
]);
if (result.success) {
console.log('Valid!', result.scrubs);
} else {
console.log('Errors:', result.errors);
}
core.sv.format()
| Format | Description |
|---|---|
upper |
Uppercase |
lower |
Lowercase |
money |
Currency |
date |
Date format |
phone |
Phone format |
nohtml |
Strip HTML |
core.sv.format('hello', 'upper');
core.sv.format(1234.56, 'money...$');
core.sv.format('5551234567', 'phone');
core.ux - User Experience
core.ux.insertPocket()
Dynamically inserts a pocket into the DOM.
core.ux.insertPocket('#main', 'home');
core.ux.insertPocket('#main', 'products', [
{ name: 'products', url: '/api/products' }
]);
core.ux.insertPocket('#main', 'header,content,footer');
core.ux.formatValue()
core.ux.formatValue('hello', 'upper');
core.ux.formatValue(' hello ', 'trim|upper');
core.ux.formatValue(1234.56, ['money*$']);
core.ud - User Defined
Configuration
core.ud.defaultDelta = 'N/A';
core.ud.defaultDateFormat = 'YYYY-MM-DD';
core.ud.defaultLoadingTemplate = '<div class="spinner"></div>';
Lifecycle Hooks
| Hook | When Called |
|---|---|
core.ud.init() |
On framework initialization |
core.ud.soc() |
Start of rendering cycle |
core.ud.pk_eol() |
End of rendering cycle |
core.ud.preflight() |
Before backend requests |
core.ud.postflight() |
After backend responses |
core.ud.prepaint() |
Before template injection |
core.ud.postpaint() |
After data cloning |
core.ud.init = () => {
core.useRouting = true;
console.log('Framework initialized');
};
core.ud.soc = () => {
console.log('Rendering started');
};
core.ud.preflight = (dataRef, dataSrc, type) => {
return {
headers: { 'Authorization': 'Bearer ' + token }
};
};
core.ud.postflight = (dataRef, dataObj, type) => {
if (dataRef === 'users') {
dataObj = dataObj.filter(u => u.active);
}
return dataObj;
};
core.ud.postpaint = (dataRef, dataObj, type) => {
console.log(`Rendered ${dataRef}`);
};
Formatters Reference
| Formatter | Input | Output |
|---|---|---|
upper |
"hello" | "HELLO" |
lower |
"HELLO" | "hello" |
upperfirst |
"hello" | "Hello" |
money |
1234.56 | "$1234.56" |
date |
timestamp | "2/3/26" |
phone |
"5551234567" | "(555) 123-4567" |
truncate |
"Long text" | "Long..." |
nohtml |
"<b>text</b>" | "text" |
linkify |
"example.com" | "<a>...</a>" |
boolean |
"true" | true |
number |
"123.45" | 123.45 |
padleft |
"5" | "005" |
padright |
"5" | "500" |
Validation Rules
| Rule | Usage | Description |
|---|---|---|
req |
['req'] | Field is required |
email |
['email'] | Valid email format |
url |
['url'] | Valid URL format |
num |
['num'] | Must be numeric |
alpha |
['alpha'] | Letters only |
alphanum |
['alphanum'] | Letters and numbers |
min |
['min:8'] | Minimum length |
max |
['max:100'] | Maximum length |
gte |
['gte:18'] | Greater than or equal |
lte |
['lte:100'] | Less than or equal |
match |
['match:password'] | Must match field |
ccnum |
['ccnum'] | Valid credit card |
Caching
core.js implements TTL-based caching for both data and templates.
// Set default cache expiration (seconds)
core.be.cacheExpireDefault = 3600; // 1 hour
// Set cache for specific data
core.be.cacheExpire = {
type: 'data',
name: 'users',
seconds: 300 // 5 minutes
};
// Set cache for template
core.be.cacheExpire = {
type: 'template',
name: 'header',
seconds: 86400 // 24 hours
};
// Check cache timestamp
const isValid = core.be.checkCacheTs('users', 'data');
Storage Tiers
Choose the appropriate storage tier based on your needs:
| Tier | Persistence | Visibility | Use Case |
|---|---|---|---|
0 - DOM |
Page only | Hidden | Sensitive data, temporary state |
1 - Static |
Page only | Visible in HTML | Public data, debugging (default) |
2 - Session |
Tab session | Hidden | User session, auth tokens |
// DOM storage (memory only)
core.cr.setData('tempState', { count: 0 }, element, 0);
// Static storage (default, visible in HTML)
core.cr.setData('users', usersArray, null, 1);
// Session storage (persists across page loads)
core.cr.setData('authToken', 'abc123', null, 2);
Example: Basic Usage
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/gh/Sitezip/core.sbs/core.js"></script>
</head>
<body>
<div id="main">
<div class="core-pocket" data-core-templates="users"></div>
</div>
<section id="cr-data" style="display:none;">
<template name="users">
<div class="core-clone" data-core-data="users">
<h3>{{rec:name}}</h3>
<p>{{rec:email}}</p>
</div>
</template>
</section>
<script>
core.ud.init = () => {
const users = [
{ name: 'John Doe', email: 'john@example.com' },
{ name: 'Jane Smith', email: 'jane@example.com' }
];
core.cr.setData('users', users);
};
</script>
</body>
</html>
Example: Form Validation
<form id="signupForm">
<input type="text" name="username" placeholder="Username">
<input type="email" name="email" placeholder="Email">
<input type="password" name="password" placeholder="Password">
<input type="password" name="confirmPassword" placeholder="Confirm">
<button type="submit">Sign Up</button>
</form>
<script>
document.getElementById('signupForm').addEventListener('submit', (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const result = core.sv.scrub([
{
name: 'username',
value: formData.get('username'),
scrubs: ['req', 'alphanum', 'min:3', 'max:20']
},
{
name: 'email',
value: formData.get('email'),
scrubs: ['req', 'email']
},
{
name: 'password',
value: formData.get('password'),
scrubs: ['req', 'min:8']
},
{
name: 'confirmPassword',
value: formData.get('confirmPassword'),
scrubs: ['req', 'match:password']
}
]);
if (result.success) {
console.log('Form valid!', result.scrubs);
// Submit to server
} else {
console.log('Validation errors:', result.errors);
// Show errors to user
}
});
</script>
Example: API Integration
<div class="core-pocket"
data-core-templates="products"
data-products-core-source="https://api.example.com/products">
</div>
<template name="products">
<div class="core-clone" data-core-data="products">
<img {{rec:image:core_pk_attr:src}} alt="{{rec:name}}">
<h3>{{rec:name}}</h3>
<p>{{rec:description:truncate:100}}</p>
<p class="price">{{rec:price:money:$}}</p>
<button onclick="addToCart('{{rec:id}}')">Add to Cart</button>
</div>
</template>
<script>
core.ud.preflight = (dataRef, dataSrc, type) => {
if (dataRef === 'products') {
return {
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('token')
}
};
}
};
core.ud.postflight = (dataRef, dataObj, type) => {
if (dataRef === 'products') {
// Filter out inactive products
return dataObj.filter(p => p.active);
}
return dataObj;
};
</script>
Example: SPA Routing
<nav>
<a href="#/_main/home">Home</a>
<a href="#/_main/about">About</a>
<a href="#/_main/products">Products</a>
<a href="#/_main/contact">Contact</a>
</nav>
<div id="main">
<div class="core-pocket" data-core-templates="home"></div>
</div>
<section id="cr-data" style="display:none;">
<template name="home">
<h1>Welcome Home</h1>
</template>
<template name="about">
<h1>About Us</h1>
</template>
<template name="products">
<h1>Our Products</h1>
<div class="core-clone" data-core-data="products">
<div>{{rec:name}} - {{rec:price:money:$}}</div>
</div>
</template>
<template name="contact">
<h1>Contact Us</h1>
</template>
</section>
<script>
core.ud.init = () => {
core.useRouting = true;
};
</script>
Example: Recursive Cloning
<div class="core-pocket" data-core-templates="users"></div>
<template name="users">
<div class="core-clone" data-core-data="users">
<h3>{{rec:name}}</h3>
<p>{{rec:email}}</p>
<!-- Recursive: render posts for each user -->
<div class="posts">
{{rec:posts:core_pk_cloner:postTemplate}}
</div>
</div>
</template>
<template name="postTemplate">
<div class="post">
<h4>{{rec:title}}</h4>
<p>{{rec:content:truncate:200}}</p>
<span>{{rec:date:date:M/D/YY}}</span>
<!-- Nested recursive: render comments for each post -->
<div class="comments">
{{rec:comments:core_pk_cloner:commentTemplate}}
</div>
</div>
</template>
<template name="commentTemplate">
<div class="comment">
<strong>{{rec:author}}</strong>: {{rec:text}}
</div>
</template>
<script>
core.ud.init = () => {
const users = [
{
name: 'John Doe',
email: 'john@example.com',
posts: [
{
title: 'First Post',
content: 'This is my first post...',
date: 1738627200,
comments: [
{ author: 'Jane', text: 'Great post!' },
{ author: 'Bob', text: 'Thanks for sharing!' }
]
}
]
}
];
core.cr.setData('users', users);
};
</script>
VS Code Extension
Accelerate your core.js development with our official VS Code extension featuring 56 intelligent code snippets, custom syntax highlighting, and a dedicated theme.
Features
- 56 Code Snippets - 26 HTML snippets + 30 JavaScript snippets
- Custom Syntax Highlighting - Grammar injection for core.js template syntax
- Dark Theme - "core.js Dark" theme optimized for the framework
- IntelliSense Integration - Autocomplete with detailed descriptions
- Lifecycle Hooks - All 7 hooks with correct signatures
- Complete Examples - Full working code for common patterns
Snippet Breakdown
HTML (26 snippets)
- • 5 Pocket variations
- • 4 Template structures
- • 4 Clone patterns
- • 9 Data directives
- • 3 Anchor shortcuts
- • 2 Complete examples
JavaScript (30 snippets)
- • 7 Lifecycle hooks
- • 5 Backend API calls
- • 3 Registry operations
- • 5 Helper functions
- • 3 Configuration setups
- • 7 Utilities & handlers
Available Snippets
Core.js Pockets
cpk
Basic pocket
cpkd
Pocket with data source
cpkt
Pocket with template
cpkid
Pocket with ID
cpknr
Pocket (no routing)
Templates
ctpl
Basic template
ctpld
Template with data refs
ctplc
Template with clone
ctplf
Full template structure
Clones
ccl
Basic clone
cclr
Clone with record refs
cclnest
Nested clone (recursive)
cclaug
Clone with augmented data
Template Directives
cdata
Data reference
crec
Record reference
caug
Augmented data
cattr
Attribute injection
ccloner
Recursive cloner
cformat
Formatted data
cdateformat
Date formatting
cmoneyformat
Money formatting
Lifecycle Hooks
cudinit
Init hook
cudsoc
Start of call hook
cudeoc
End of call hook
cudpre
Preflight hook
cudpost
Postflight hook
cudprepaint
Prepaint hook
cudpostpaint
Postpaint hook
API Calls
cbeget
Get data
cbegetset
Get data with settings
cbetpl
Get template
cbepost
POST data
cpkinit
Initialize pockets
ccrset
Set data in registry
ccrget
Get data from registry
ccrgettpl
Get template from registry
Helper Functions
chfdig
Deep object access
chfdate
Date formatting
chfhydrate
Hydrate by class
chfformat
Format by class
chfparse
Parse JSON
Validation & Utilities
csvscrub
Scrub array
csvformat
Format value
caget
Anchor get data
catpl
Anchor get template
capk
Anchor reinit pockets
cexample
Complete example
cform
Form with validation
💡 Pro Tip: Type any snippet prefix (like cpk, ctpl, ccl) and press Tab or Enter to expand!
Installation
📦 Recommended: Download from GitHub Releases
- 1. Go to GitHub Releases
- 2. Download the latest
corejs-snippets-*.vsixfile - 3. Open VS Code
- 4. Press
Ctrl+Shift+P(orCmd+Shift+Pon Mac) - 5. Type "Extensions: Install from VSIX"
- 6. Select the downloaded
.vsixfile - 7. Reload VS Code (
Ctrl+Shift+P→ "Developer: Reload Window")
Alternative: Build from Source
1. Install vsce
npm install -g @vscode/vsce
2. Navigate to extension directory
cd vscode-extension
3. Package the extension
vsce package
This creates a .vsix file
4. Install in VS Code
- • Open VS Code
- • Press
Ctrl+Shift+P(orCmd+Shift+Pon Mac) - • Type "Extensions: Install from VSIX"
- • Select the generated
.vsixfile
5. Reload VS Code
Press Ctrl+Shift+P → "Developer: Reload Window"
Common Snippets
HTML Snippets
cpk |
Basic pocket |
cpkd |
Pocket with data source |
ctpl |
Basic template |
ctplc |
Template with clone |
ccl |
Basic clone |
crec |
Record reference |
JavaScript Snippets
cudinit |
Init hook |
cudsoc |
Start of call hook |
cbeget |
Get data from API |
cpkinit |
Initialize pockets |
ccrset |
Set data in registry |
csvscrub |
Validate data |
Usage Example
Type a snippet prefix and press Tab or Enter to expand:
<!-- Type: cpkd + Tab -->
<div class="core-pocket"
data-core-templates="users"
data-core-source-users="https://api.example.com/users">
</div>
💡 Pro Tip: Press Ctrl+Space to trigger
IntelliSense and see all available snippets.
Verify Installation
- Open an HTML file in VS Code
- Type
cpkand press Tab - The pocket snippet should expand automatically
Additional Resources
GitHub Repository
https://github.com/Sitezip/core.sbsOfficial Website
https://core.sbsVS Code Extension
Located in /vscode-extension directory
Version
Current: 20260125.1