Pick your app

The examples below will be updated with your app ID.

Introduction

Getting started with Vanilla JS

You can use Instant with plain ol' Javascript/Typescript too. You may find this helpful to integrate Instant with a framework that doesn't have an official SDK yet.

To use Instant in a brand new project fire up your terminal set up a new project with Vite.

npm create vite@latest instant-vanilla
# Choose Vanilla
# Choose Typescript

Now head into your project directory and install the core package:

cd instant-vanilla
npm i @instantdb/core
npm run dev

Now open up src/main.ts in your favorite editor and replace the entirety of the file with the following code.

import { init, tx, id } from '@instantdb/core';

// Visit https://instantdb.com/dash to get your APP_ID :)
const APP_ID = '__APP_ID__'

// Optional: Declare your schema for intellisense!
interface Todo {
  id: string;
  text: string;
  done: boolean;
  createdAt: number;
}

type Schema = {
  todos: Todo;
};

// Initialize the database
// ---------
const db = init<Schema>({ appId: APP_ID });

// Subscribe to data
// ---------
db.subscribeQuery({ todos: {} }, (resp) => {
  if (resp.error) {
    renderError(resp.error.message); // Pro-tip: Check you have the right appId!
    return;
  }
  if (resp.data) {
    render(resp.data);
  }
});

// Write Data
// ---------
function addTodo(text: string) {
  db.transact(
    tx.todos[id()].update({
      text,
      done: false,
      createdAt: Date.now(),
    })
  );
  focusInput();
}

function deleteTodoItem(todo: Todo) {
  db.transact(tx.todos[todo.id].delete());
}

function toggleDone(todo: Todo) {
  db.transact(tx.todos[todo.id].update({ done: !todo.done }));
}

function deleteCompleted(todos: Todo[]) {
  const completed = todos.filter((todo) => todo.done);
  const txs = completed.map((todo) => tx.todos[todo.id].delete());
  db.transact(txs);
}

function toggleAllTodos(todos: Todo[]) {
  const newVal = !todos.every((todo) => todo.done);
  db.transact(todos.map((todo) => tx.todos[todo.id].update({ done: newVal })));
}

// Styles
// ---------
const styles: Record<string, string> = {
  container: `
    box-sizing: border-box;
    background-color: #fafafa;
    font-family: code, monospace;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
  `,
  header: `
    letter-spacing: 2px;
    font-size: 50px;
    color: lightgray;
    margin-bottom: 10px;
  `,
  form: `
    box-sizing: inherit;
    display: flex;
    border: 1px solid lightgray;
    border-bottom-width: 0px;
    width: 350px;
  `,
  toggleAll: `
    font-size: 30px;
    cursor: pointer;
    margin-left: 11px;
    margin-top: -6px;
    width: 15px;
    margin-right: 12px;
  `,
  input: `
    background-color: transparent;
    font-family: code, monospace;
    width: 287px;
    padding: 10px;
    font-style: italic;
  `,
  todoList: `
    box-sizing: inherit;
    width: 350px;
  `,
  checkbox: `
    font-size: 30px;
    margin-left: 5px;
    margin-right: 20px;
    cursor: pointer;
  `,
  todo: `
    display: flex;
    align-items: center;
    padding: 10px;
    border: 1px solid lightgray;
    border-bottom-width: 0px;
  `,
  todoText: `
    flex-grow: 1;
    overflow: hidden;
  `,
  delete: `
    width: 25px;
    cursor: pointer;
    color: lightgray;
  `,
  actionBar: `
    display: flex;
    justify-content: space-between;
    width: 328px;
    padding: 10px;
    border: 1px solid lightgray;
    font-size: 10px;
  `,
  footer: `
    margin-top: 20px;
    font-size: 10px;
  `,
};

// Render
// ---------
const app = document.getElementById('app')!;
app.style.cssText = styles.container;

function render(data: { todos: Todo[] }) {
  app.innerHTML = '';

  const { todos } = data;

  const containerHTML = `
    <div style="${styles.container}">
      <div style="${styles.header}">todos</div>
      ${TodoForm()}
      ${TodoList(todos)}
      ${ActionBar(todos)}
      <div style="${styles.footer}">Open another tab to see todos update in realtime!</div>
    </div>
  `;

  app.innerHTML = containerHTML;

  // Attach event listeners
  document.querySelector('.toggle-all')?.addEventListener('click', () => toggleAllTodos(todos));
  document.querySelector('form')?.addEventListener('submit', submitForm);
  todos.forEach(todo => {
    document.getElementById(`toggle-${todo.id}`)?.addEventListener('change', () => toggleDone(todo));
    document.getElementById(`delete-${todo.id}`)?.addEventListener('click', () => deleteTodoItem(todo));
  });
  document.querySelector('.delete-completed')?.addEventListener('click', () => deleteCompleted(todos));
}

function renderError(errorMessage: string) {
  app.innerHTML = `
    <div>${errorMessage}</div>
  `;
}


function TodoForm() {
  return `
    <div style="${styles.form}">
      <div class="toggle-all" style="${styles.toggleAll}">⌄</div>
      <form>
        <input style="${styles.input}" placeholder="What needs to be done?" type="text" autofocus>
      </form>
    </div>
  `;
}

function TodoList(todos: Todo[]) {
  return `
    <div style="${styles.todoList}">
      ${todos.map(todo => `
        <div style="${styles.todo}">
          <input id="toggle-${todo.id}" type="checkbox" style="${styles.checkbox}" ${todo.done ? 'checked' : ''}>
          <div style="${styles.todoText}">
            ${todo.done ? `<span style="text-decoration: line-through;">${todo.text}</span>` : `<span>${todo.text}</span>`}
          </div>
          <span id="delete-${todo.id}" style="${styles.delete}">𝘟</span>
        </div>
      `).join('')}
    </div>
  `;
}

function ActionBar(todos: Todo[]) {
  return `
    <div style="${styles.actionBar}">
      <div>Remaining todos: ${todos.filter(todo => !todo.done).length}</div>
      <div class="delete-completed" style="cursor: pointer;">Delete Completed</div>
    </div>
  `;
}

function focusInput() {
  const input = document.querySelector<HTMLInputElement>('input[type="text"]');
  if (input) {
    input.focus();
  }
}

function submitForm(event: Event) {
  event.preventDefault();
  const input = (event.target as HTMLFormElement).querySelector('input');
  if (input && input.value.trim()) {
    addTodo(input.value);
    input.value = '';
  }
}

Go to localhost:5173 and follow the final instruction to load the app!

Huzzah 🎉 You've got your first Instant web app running! Check out the Explore section to learn more about how to use Instant :)

Previous
Getting started w/ React Native