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.
npx create-vite@latest -t vanilla-ts instant-vanilla 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, i, id, InstaQLEntity } from "@instantdb/core"; // Visit https://instantdb.com/dash to get your APP_ID :) const APP_ID = "__APP_ID__"; // Optional: Declare your schema! const schema = i.schema({ entities: { todos: i.entity({ text: i.string(), done: i.boolean(), createdAt: i.date(), }), }, }); type Todo = InstaQLEntity<typeof schema, "todos">; // Initialize the database // --------- const db = init({ appId: APP_ID, schema }); // 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( db.tx.todos[id()].update({ text, done: false, createdAt: Date.now(), }) ); focusInput(); } function deleteTodoItem(todo: Todo) { db.transact(db.tx.todos[todo.id].delete()); } function toggleDone(todo: Todo) { db.transact(db.tx.todos[todo.id].update({ done: !todo.done })); } function deleteCompleted(todos: Todo[]) { const completed = todos.filter((todo) => todo.done); const txs = completed.map((todo) => db.tx.todos[todo.id].delete()); db.transact(txs); } function toggleAllTodos(todos: Todo[]) { const newVal = !todos.every((todo) => todo.done); db.transact( todos.map((todo) => db.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 Working with data section to learn more about how to use Instant :)