Interactive Tutorial

Build a Todo Appwith core.js

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.

✨ Live Demo

Try it now

This is what you'll build. Try adding, checking, and deleting todos:

📊 App Stats

0
Total Todos
0
Completed
0
Remaining

📚 How To Build It

Follow these steps to build your own todo app from scratch:

0

Start with Basic HTML + CDN

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.

1

Add a Pocket

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.

2

Add the Template

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 items
3

Initialize with Data

Add 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 everything
  • • Each todo needs an id for tracking
4

Add Functions

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>
5

Add Custom Formatters

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>

📄 Complete Code

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.

🎯 Key Concepts You Just Learned

📦

Pockets

Containers that hold dynamic content. Just add core-pocket class.

📝

Templates

Reusable HTML patterns with data binding using {{rec:field}} syntax.

🔄

Clone

Automatically loops through arrays. No manual iteration needed.

💾

State Management

Use core.cr.setData() to update state and trigger re-renders.

🚀

You're Ready to Build!

You've just built a working todo app with core.js. You now understand the fundamentals: pockets, templates, data binding, and state management.

📚 Learn More

🛠️ CLI Tools

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