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

  1. SOC (Start of Call) - Initialization begins
  2. getTemplate() - Fetch missing templates
  3. addTemplate() - Inject templates into pockets
  4. getData() - Fetch missing data
  5. addData() - Clone and populate with data
  6. 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

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. 1. Go to GitHub Releases
  2. 2. Download the latest corejs-snippets-*.vsix file
  3. 3. Open VS Code
  4. 4. Press Ctrl+Shift+P (or Cmd+Shift+P on Mac)
  5. 5. Type "Extensions: Install from VSIX"
  6. 6. Select the downloaded .vsix file
  7. 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 (or Cmd+Shift+P on Mac)
  • • Type "Extensions: Install from VSIX"
  • • Select the generated .vsix file

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

  1. Open an HTML file in VS Code
  2. Type cpk and press Tab
  3. The pocket snippet should expand automatically

Additional Resources

GitHub Repository

https://github.com/Sitezip/core.sbs

Official Website

https://core.sbs

VS Code Extension

Located in /vscode-extension directory

Version

Current: 20260125.1