# Jazz ## Documentation ### Getting started #### Introduction # Learn some Jazz Welcome to the Jazz documentation! The Jazz docs are currently heavily work in progress, sorry about that! ## Quickstart You can use [`create-jazz-app`](/docs/tools/create-jazz-app) to create a new Jazz project from one of our starter templates or example apps: ```sh npx create-jazz-app@latest --api-key you@example.com ``` Or set up Jazz yourself, using the following instructions for your framework of choice: - [React](/docs/react/project-setup) - [Next.js](/docs/react/project-setup#nextjs) - [React Native](/docs/react-native/project-setup) - [React Native Expo](/docs/react-native-expo/project-setup) - [Vue](/docs/vue/project-setup) - [Svelte](/docs/svelte/project-setup) Or you can follow this [React step-by-step guide](/docs/react/guide) where we walk you through building an issue tracker app. ## Example apps You can also find [example apps](/examples) with code most similar to what you want to build. These apps make use of different features such as auth, file upload, and more. ## Sync and storage Sync and persist your data by setting up a [sync and storage infrastructure](/docs/sync-and-storage) using Jazz Cloud, or do it yourself. ## Collaborative values Learn how to structure your data using [collaborative values](/docs/schemas/covalues). ## API Reference Many of the packages provided are documented in the [API Reference](/api-reference). ## LLM Docs Get better results with AI by [importing the Jazz docs](/docs/ai-tools) into your context window. ## Get support If you have any questions or need assistance, please don't hesitate to reach out to us on [Discord](https://discord.gg/utDMjHYg42). We would love to help you get started. #### Guide ### react Implementation # React guide This is a step-by-step tutorial where we'll build an issue tracker app using React. You'll learn how to set up a Jazz app, use Jazz Cloud for sync and storage, create and manipulate data using Collaborative Values (CoValues), build a UI and subscribe to changes, set permissions, and send invites. ## Project setup 1. Create a project called "circular" from a generic Vite starter template: {/* prettier-ignore */} ```bash npx degit gardencmp/vite-ts-react-tailwind circular cd circular npm install npm run dev ``` You should now have an empty app running, typically at [localhost:5173](http://localhost:5173).
(If you make changes to the code, the app will automatically refresh.) 2. Install `jazz-tools` and `jazz-react`
(in a new terminal window): {/* prettier-ignore */} ```bash cd circular npm install jazz-tools jazz-react ``` 3. Modify `src/main.tsx` to set up a Jazz context: {/* prettier-ignore */} ```tsx import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App.tsx"; import "./index.css"; import { JazzProvider } from "jazz-react"; // [!code ++] ReactDOM.createRoot(document.getElementById("root")!).render( ); ``` This sets Jazz up and wraps our app in the provider. {/* TODO: explain Auth */} ## Intro to CoValues Let's learn about the **central idea** behind Jazz: **Collaborative Values.** What if we could **treat distributed state like local state?** That's what CoValues do. We can - **create** CoValues, anywhere - **load** CoValues by `ID`, from anywhere else - **edit** CoValues, from anywhere, by mutating them like local state - **subscribe to edits** in CoValues, whether they're local or remote ### Declaring our own CoValues To make our own CoValues, we first need to declare a schema for them. Think of a schema as a combination of TypeScript types and runtime type information. Let's start by defining a schema for our most central entity in Circular: an **Issue.** Create a new file `src/schema.ts` and add the following: ```ts export class Issue extends CoMap { title = co.string; description = co.string; estimate = co.number; status = co.optional.literal("backlog", "in progress", "done"); } ``` {/* TODO: explain what's happening */} ### Reading from CoValues CoValues are designed to be read like simple local JSON state. Let's see how we can read from an Issue by building a component to render one. Create a new file `src/components/Issue.tsx` and add the following: {/* prettier-ignore */} ```tsx export function IssueComponent({ issue }: { issue: Issue }) { return (

{issue.title}

{issue.description}

Estimate: {issue.estimate}

Status: {issue.status}

); } ```
Simple enough! ### Creating CoValues To actually see an Issue, we have to create one. This is where things start to get interesting... Let's modify `src/App.tsx` to prepare for creating an Issue and then rendering it: {/* prettier-ignore */} ```tsx function App() { const [issue, setIssue] = useState(); if (issue) { return ; } else { return ; } } export default App; ``` Now, finally, let's implement creating an issue: {/* prettier-ignore */} ```tsx function App() { const [issue, setIssue] = useState(); const createIssue = () => { // [!code ++:11] const newIssue = Issue.create( { title: "Buy terrarium", description: "Make sure it's big enough for 10 snails.", estimate: 5, status: "backlog", }, ); setIssue(newIssue); }; if (issue) { return ; } else { return ; } } export default App; ``` 🏁 Now you should be able to create a new issue by clicking the button and then see it rendered!
Preview

Buy terrarium

Make sure it's big enough for 10 snails.

Estimate: 5

Status: backlog

We'll already notice one interesting thing here: - We have to create every CoValue with an `owner`! - this will determine access rights on the CoValue, which we'll learn about in "Groups & Permissions" - here the `owner` is set automatically to a group managed by the current user because we have not declared any **Behind the scenes, Jazz not only creates the Issue in memory but also automatically syncs an encrypted version to the cloud and persists it locally. The Issue also has a globally unique ID.** We'll make use of both of these facts in a bit, but for now let's start with local editing and subscribing. ### Editing CoValues and subscribing to edits Since we're the owner of the CoValue, we should be able to edit it, right? And since this is a React app, it would be nice to subscribe to edits of the CoValue and reactively re-render the UI, like we can with local state. This is exactly what the `useCoState` hook is for! - Note that `useCoState` doesn't take a CoValue directly, but rather a CoValue's schema, plus its `ID`. - So we'll slightly adapt our `useState` to only keep track of an issue ID... - ...and then use `useCoState` to get the actual issue Let's modify `src/App.tsx`: {/* prettier-ignore */} ```tsx function App() { const [issue, setIssue] = useState(); // [!code --] const [issueID, setIssueID] = useState>(); // [!code ++] const issue = useCoState(Issue, issueID); // [!code ++] const createIssue = () => { const newIssue = Issue.create( { title: "Buy terrarium", description: "Make sure it's big enough for 10 snails.", estimate: 5, status: "backlog", }, ); setIssueID(newIssue.id); }; if (issue) { return ; } else { return ; } } export default App; ``` And now for the exciting part! Let's make `src/components/Issue.tsx` an editing component. {/* prettier-ignore */} ```tsx export function IssueComponent({ issue }: { issue: Issue }) { return (
{ issue.title = event.target.value }}/>