diff --git a/docs/pages/get-started/nextjs.mdx b/docs/pages/get-started/nextjs.mdx
index 24456dfad8..75bcf9150a 100644
--- a/docs/pages/get-started/nextjs.mdx
+++ b/docs/pages/get-started/nextjs.mdx
@@ -109,25 +109,144 @@ the [`@liveblocks/react`](/docs/api-reference/liveblocks-react) package.
- Use the Liveblocks hooks
+ Create a multiplayer input
- Now that we’re connected to a room, we can start using the Liveblocks hooks.
- The first we’ll add is [`useOthers`](/docs/api-reference/liveblocks-react#useOthers), a hook that provides information
- about which other users are connected to the room.
+ From this point, you can use Liveblocks hooks to create your multiplayer app. For example, you can create
+ a shared input that stays in sync across users. To set it up, first [define your storage
+ type](/docs/api-reference/liveblocks-client#Typing-your-data) in `liveblocks.config.ts`. An `input` [`LiveObject`](/docs/api-reference/liveblocks-client#LiveObject)
+ can store the text of the input.
+
+ ```ts file="liveblocks.config.ts"
+ import { LiveObject } from "@liveblocks/client";
+
+ declare global {
+ interface Liveblocks {
+ // +++
+ Storage: {
+ input: LiveObject<{ text: string }>;
+ };
+ // +++
+ }
+ }
+
+ export {};
+ ```
+
+ Next, set an initial value for `input` on [`RoomProvider`](/docs/api-reference/liveblocks-react#RoomProvider),
+ a new `LiveObject` with a `text` value.
- ```tsx file="app/CollaborativeApp.tsx" highlight="6"
+ ```tsx file="app/Room.tsx"
"use client";
- import { useOthers } from "@liveblocks/react/suspense";
+ import { ReactNode } from "react";
+ import { LiveObject } from "@liveblocks/client";
+ import {
+ LiveblocksProvider,
+ RoomProvider,
+ ClientSideSuspense,
+ } from "@liveblocks/react/suspense";
+
+ export function Room({ children }: { children: ReactNode }) {
+ return (
+
+
+ Loading…}>
+ {children}
+
+
+
+ );
+ }
+ ```
+
+ Now, use [`useStorage`](/docs/api-reference/liveblocks-react#useStorage) to read the value of `input.text` and
+ [`useMutation`](/docs/api-reference/liveblocks-react#useMutation) to update it.
+
+ ```tsx file="app/CollaborativeApp.tsx"
+ "use client";
+
+ import { useStorage, useMutation } from "@liveblocks/react/suspense";
export function CollaborativeApp() {
+ // +++
+ const text = useStorage((root) => root.input.text);
+ // +++
+
+ // +++
+ const updateText = useMutation(({ storage }, newText: string) => {
+ const input = storage.get("input");
+ input.set("text", newText);
+ }, []);
+ // +++
+
+ return (
+ updateText(e.target.value)}
+ // +++
+ placeholder="Start typing…"
+ />
+ );
+ }
+ ```
+
+ Open your app in two browser tabs to see the input update in realtime.
+
+
+
+
+
+ Show custom presence
+
+
+ [`useOthers`](/docs/api-reference/liveblocks-react#useOthers) allows you to
+ access a list of users that are currently connected to the room. Build a
+ simple avatar stack from the list of connected users.
+
+ ```tsx file="app/Avatars.tsx"
+ "use client";
+
+ import { useOthers } from "@liveblocks/react/suspense";
+
+ export function Avatars() {
+ // +++
const others = useOthers();
- const userCount = others.length;
- return
+ );
}
```
+ Open your app in two browser tabs to see avatars appear for each user.
+
diff --git a/docs/pages/get-started/react.mdx b/docs/pages/get-started/react.mdx
index 6de277eec3..48c0843166 100644
--- a/docs/pages/get-started/react.mdx
+++ b/docs/pages/get-started/react.mdx
@@ -106,26 +106,144 @@ collaboration to your React application using the hooks from the
- Use the Liveblocks hooks
+ Create a multiplayer input
- Now that we’re connected to a room, we can start using the Liveblocks hooks.
- The first we’ll add is [`useOthers`](/docs/api-reference/liveblocks-react#useOthers), a hook that provides information about
- which other users are connected to the room.
+ From this point, you can use Liveblocks hooks to create your multiplayer app. For example, you can create
+ a shared input that stays in sync across users. To set it up, first [define your storage
+ type](/docs/api-reference/liveblocks-client#Typing-your-data) in `liveblocks.config.ts`. An `input` [`LiveObject`](/docs/api-reference/liveblocks-client#LiveObject)
+ can store the text of the input.
+
+ ```ts file="liveblocks.config.ts"
+ import { LiveObject } from "@liveblocks/client";
+
+ declare global {
+ interface Liveblocks {
+ // +++
+ Storage: {
+ input: LiveObject<{ text: string }>;
+ };
+ // +++
+ }
+ }
+
+ export {};
+ ```
- ```tsx file="Room.tsx" highlight="6"
+ Next, set an initial value for `input` on [`RoomProvider`](/docs/api-reference/liveblocks-react#RoomProvider),
+ a new `LiveObject` with a `text` value.
+
+ ```tsx file="App.tsx"
"use client";
- import { useOthers } from "./liveblocks.config";
+ import { LiveObject } from "@liveblocks/client";
+ import {
+ LiveblocksProvider,
+ RoomProvider,
+ ClientSideSuspense,
+ } from "@liveblocks/react/suspense";
+ import { Room } from "./Room";
+
+ export default function App() {
+ return (
+
+
+ Loading…}>
+
+
+
+
+ );
+ }
+ ```
+
+ Now, use [`useStorage`](/docs/api-reference/liveblocks-react#useStorage) to read the value of `input.text` and
+ [`useMutation`](/docs/api-reference/liveblocks-react#useMutation) to update it.
+
+ ```tsx file="Room.tsx"
+ "use client";
+
+ import { useStorage, useMutation } from "@liveblocks/react/suspense";
export function Room() {
+ // +++
+ const text = useStorage((root) => root.input.text);
+ // +++
+
+ // +++
+ const updateText = useMutation(({ storage }, newText: string) => {
+ const input = storage.get("input");
+ input.set("text", newText);
+ }, []);
+ // +++
+
+ return (
+ updateText(e.target.value)}
+ // +++
+ placeholder="Start typing…"
+ />
+ );
+ }
+ ```
+
+ Open your app in two browser tabs to see the input update in realtime.
+
+
+
+
+
+ Show custom presence
+
+
+ [`useOthers`](/docs/api-reference/liveblocks-react#useOthers) allows you to
+ access a list of users that are currently connected to the room. Build a
+ simple avatar stack from the list of connected users.
+
+ ```tsx file="Avatars.tsx"
+ "use client";
+
+ import { useOthers } from "@liveblocks/react/suspense";
+
+ export function Avatars() {
+ // +++
const others = useOthers();
- const userCount = others.length;
+ // +++
- return