Learn core.js by building a real application from scratch. No build tools, no npm, no dependencies - just one CDN link and you're ready to go.
This is what you'll build. Try adding, checking, and deleting todos:
Follow these steps to build your own todo app from scratch:
This is the foundation. Create a new HTML file with this complete structure. core.js works entirely through a CDN link - no npm, no build tools, no installation:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Todo App - core.js</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-slate-900 text-white p-8">
<div class="max-w-2xl mx-auto">
<h1 class="text-4xl font-bold mb-8">My Todo App</h1>
<!-- Content will go here -->
</div>
<!-- Load core.js from CDN -->
<script src="https://cdn.jsdelivr.net/gh/Sitezip/core.sbs/core.js"></script>
</body>
</html>
💡 Save this as todo.html and open it
in your browser to test.
A core-pocket is where core.js
injects content. Replace the comment
with:
<!-- The pocket - core.js will fill this --> <div class="core-pocket" data-core-templates="todoApp"></div>
💡 The data-core-templates="todoApp"
tells core.js which template to load here.
Templates go in a hidden <section id="cr-data">. Add this BEFORE the core.js script tag:
<!-- Templates (hidden) -->
<section id="cr-data" style="display:none;">
<template name="todoApp">
<form onsubmit="addTodo(event)" class="flex gap-2 mb-4">
<input type="text" id="todoInput" placeholder="What needs to be done?"
class="flex-1 px-4 py-2 bg-slate-800 border border-slate-700 rounded text-white">
<button type="submit" class="px-6 py-2 bg-emerald-500 rounded">Add</button>
</form>
<div class="core-clone" data-core-data="todos">
<div class="flex items-center gap-3 p-4 bg-slate-800 rounded mb-2">
<input type="checkbox" onchange="toggleTodo({{rec:id}})"
{{rec:done:core_pk_checked}} class="w-5 h-5">
<span class="flex-1 {{rec:done:core_pk_strikethrough}}">{{rec:text}}</span>
<button onclick="deleteTodo({{rec:id}})" class="text-red-400">Delete</button>
</div>
</div>
</template>
</section>
🔍 What's happening here:
core-clone duplicates for each todo item
{{rec:text}} shows the todo text{{rec:done:core_pk_checked}} adds
"checked" if done{{rec:done:core_pk_strikethrough}}
strikes through completed itemsAdd a script tag AFTER core.js to set up your data and initialize:
<script>
let todos = [
{ id: 1, text: 'Learn core.js', done: false },
{ id: 2, text: 'Build an app', done: false }
];
core.cr.setData('todos', todos);
core.init();
</script>
🔍 What's happening:
core.cr.setData() stores the todos array
core.init() renders everythingid for tracking
Add the functions for add, toggle, and delete. Put these BEFORE core.init():
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Todo App - core.js</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-slate-900 text-white p-8">
<div class="max-w-2xl mx-auto">
<h1 class="text-4xl font-bold mb-8">My Todo App</h1>
<div class="core-pocket" data-core-templates="todoApp"></div>
</div>
<section id="cr-data" style="display:none;">
<template name="todoApp">
<form onsubmit="addTodo(event)" class="flex gap-2 mb-4">
<input type="text" id="todoInput" placeholder="What needs to be done?"
class="flex-1 px-4 py-2 bg-slate-800 border border-slate-700 rounded text-white">
<button type="submit" class="px-6 py-2 bg-emerald-500 rounded">Add</button>
</form>
<div class="core-clone" data-core-data="todos">
<div class="flex items-center gap-3 p-4 bg-slate-800 rounded mb-2">
<input type="checkbox" onchange="toggleTodo({{rec:id}})"
{{rec:done:core_pk_checked}} class="w-5 h-5">
<span class="flex-1 {{rec:done:core_pk_strikethrough}}">{{rec:text}}</span>
<button onclick="deleteTodo({{rec:id}})" class="text-red-400">Delete</button>
</div>
</div>
</template>
</section>
<script src="https://cdn.jsdelivr.net/gh/Sitezip/core.sbs/core.js"></script>
<script>
let todos = [
{ id: 1, text: 'Learn core.js', done: false },
{ id: 2, text: 'Build an app', done: false }
];
function addTodo(event) {
event.preventDefault();
const input = document.getElementById('todoInput');
const text = input.value.trim();
if (text) {
todos.push({ id: Date.now(), text, done: false });
input.value = '';
updateTodos();
}
}
function toggleTodo(id) {
const todo = todos.find(t => t.id === id);
if (todo) {
todo.done = !todo.done;
updateTodos();
}
}
function deleteTodo(id) {
todos = todos.filter(t => t.id !== id);
updateTodos();
}
function updateTodos() {
core.cr.setData('todos', todos);
core.pk.soc();
}
core.cr.setData('todos', todos);
core.init();
</script>
</body>
</html>
To make checkboxes and strikethrough work, add this formatter BEFORE core.init(). This is the COMPLETE
working file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Todo App - core.js</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-slate-900 text-white p-8">
<div class="max-w-2xl mx-auto">
<h1 class="text-4xl font-bold mb-8">My Todo App</h1>
<div class="core-pocket" data-core-templates="todoApp"></div>
</div>
<section id="cr-data" style="display:none;">
<template name="todoApp">
<form onsubmit="addTodo(event)" class="flex gap-2 mb-4">
<input type="text" id="todoInput" placeholder="What needs to be done?"
class="flex-1 px-4 py-2 bg-slate-800 border border-slate-700 rounded text-white">
<button type="submit" class="px-6 py-2 bg-emerald-500 hover:bg-emerald-600 rounded font-semibold">Add</button>
</form>
<div class="core-clone" data-core-data="todos">
<div class="flex items-center gap-3 p-4 bg-slate-800 rounded hover:bg-slate-700 transition-colors mb-2">
<input type="checkbox" onchange="toggleTodo({{rec:id}})"
{{rec:done:core_pk_checked}} class="w-5 h-5 cursor-pointer" style="accent-color: #10b981;">
<span class="flex-1 {{rec:done:core_pk_strikethrough}}">{{rec:text}}</span>
<button onclick="deleteTodo({{rec:id}})"
class="px-3 py-1 text-red-400 hover:text-red-300 hover:bg-red-500/10 rounded">Delete</button>
</div>
</div>
</template>
</section>
<script src="https://cdn.jsdelivr.net/gh/Sitezip/core.sbs/core.js"></script>
<script>
let todos = [
{ id: 1, text: 'Learn core.js', done: false },
{ id: 2, text: 'Build an app', done: false }
];
function addTodo(event) {
event.preventDefault();
const input = document.getElementById('todoInput');
const text = input.value.trim();
if (text) {
todos.push({ id: Date.now(), text, done: false });
input.value = '';
updateTodos();
}
}
function toggleTodo(id) {
const todo = todos.find(t => t.id === id);
if (todo) {
todo.done = !todo.done;
updateTodos();
}
}
function deleteTodo(id) {
todos = todos.filter(t => t.id !== id);
updateTodos();
}
function updateTodos() {
core.cr.setData('todos', todos);
core.pk.soc();
}
// Custom formatters
core.ud.format = function(value, formatStr) {
if (formatStr === 'core_pk_checked') return value ? 'checked' : '';
if (formatStr === 'core_pk_strikethrough') return value ? 'line-through opacity-50' : '';
return value;
};
core.cr.setData('todos', todos);
core.init();
</script>
</body>
</html>
Copy this entire file and save it as todo.html - it's a complete, working
todo app:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Todo App - core.js</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-slate-900 text-white p-8">
<!-- Pocket -->
<div class="max-w-2xl mx-auto">
<h1 class="text-4xl font-bold mb-8">My Todo App</h1>
<div class="core-pocket" data-core-templates="todoApp"></div>
</div>
<!-- Templates -->
<section id="cr-data" style="display:none;">
<template name="todoApp">
<form onsubmit="addTodo(event)" class="flex gap-2 mb-4">
<input type="text" id="todoInput" placeholder="What needs to be done?"
class="flex-1 px-4 py-2 bg-slate-800 border border-slate-700 rounded text-white">
<button type="submit" class="px-6 py-2 bg-emerald-500 hover:bg-emerald-600 rounded font-semibold">Add</button>
</form>
<div class="space-y-2">
<div class="core-clone" data-core-data="todos">
<div class="flex items-center gap-3 p-4 bg-slate-800 rounded hover:bg-slate-700 transition-colors">
<input type="checkbox" onchange="toggleTodo({{rec:id}})"
{{rec:done:core_pk_checked}} class="w-5 h-5 cursor-pointer" style="accent-color: #10b981;">
<span class="flex-1 {{rec:done:core_pk_strikethrough}}">{{rec:text}}</span>
<button onclick="deleteTodo({{rec:id}})"
class="px-3 py-1 text-red-400 hover:text-red-300 hover:bg-red-500/10 rounded">Delete</button>
</div>
</div>
</div>
</template>
</section>
<!-- Load core.js from CDN -->
<script src="https://cdn.jsdelivr.net/gh/Sitezip/core.sbs/core.js"></script>
<!-- App Logic -->
<script>
let todos = [
{ id: 1, text: 'Learn core.js', done: false },
{ id: 2, text: 'Build a todo app', done: false }
];
function addTodo(event) {
event.preventDefault();
const input = document.getElementById('todoInput');
const text = input.value.trim();
if (text) {
todos.push({ id: Date.now(), text, done: false });
input.value = '';
updateTodos();
}
}
function toggleTodo(id) {
const todo = todos.find(t => t.id === id);
if (todo) {
todo.done = !todo.done;
updateTodos();
}
}
function deleteTodo(id) {
todos = todos.filter(t => t.id !== id);
updateTodos();
}
function updateTodos() {
core.cr.setData('todos', todos);
core.pk.soc();
}
// Custom formatters for checkbox and strikethrough
core.ud.format = function(value, formatStr) {
if (formatStr === 'core_pk_checked') return value ? 'checked' : '';
if (formatStr === 'core_pk_strikethrough') return value ? 'line-through opacity-50' : '';
return value;
};
// Initialize
core.cr.setData('todos', todos);
core.init();
</script>
</body>
</html>
💡 To run: Save this file and open it in your browser. That's it! No build step, no npm install, nothing else needed.
Containers that hold dynamic content. Just add core-pocket class.
Reusable HTML patterns with data binding using {{rec:field}} syntax.
Automatically loops through arrays. No manual iteration needed.
Use core.cr.setData() to
update state and trigger re-renders.
You've just built a working todo app with core.js. You now understand the fundamentals: pockets, templates, data binding, and state management.
Scaffold new projects instantly with our CLI tools:
create-core-app
npx create-core-app my-app
Create a new core.js project with templates and examples
core-gen
npx core-gen component MyComponent
Generate components, templates, and boilerplate code
core-dev
npx core-dev
Development server with hot reload and debugging tools