Today we're introducing a new set of ready-made React components, designed to
help you start integrating realtime collaboration into your product.

- [&lt;AvatarStack /&gt;](#avatar-stack): A realtime list of avatars
  representing connected users.
- [&lt;Cursors /&gt;](#cursors): A set of realtime cursors for other users in
  the room.
- [&lt;Cursor /&gt;](#cursor): A single customizable cursor component.
- [&lt;CommentPin /&gt;](#comment-pin): An avatar pin useful for toggling pop-up
  threads.
- [&lt;FloatingComposer /&gt;](#floating-composer): A pop-up composer for
  creating threads.
- [&lt;FloatingThread /&gt;](#floating-thread): A pop-up comment thread.

Additionally, we've written a new set of Next.js get started guides to help you
use them in various scenarios.

- [Draggable comments](#draggable-comments): Add a 2D canvas of draggable
  comments.
- [Table comments](#table-comments): Add pop-up comments to your AG Grid or HTML
  table.
- [Presence](#presence): Add live cursors and avatar stacks to your product.

## Components

### &lt;AvatarStack /&gt; [#avatar-stack]

Displays an overlapping stack of avatars representing users currently present in
the room. It updates in realtime as users connect and disconnect.

<PreBuiltComponentAvatarStack />

#### Features

- Pop-up username when hovering over an avatar.
- Define how many avatars should be shown before grouping the rest.
- Optionally add offline users to the stack, such as those previously connected.

Learn more in our documentation:
[`AvatarStack`](/docs/api-reference/liveblocks-react-ui#AvatarStack).

### &lt;Cursors /&gt; [#cursors]

Displays a realtime multiplayer cursor for every other user connected to the
room.

<PreBuiltComponentCursors />

#### Features

- Smooth movement using spring interpolation.
- Cursors positioned relative to their container using percentage coordinates.
- Avoids performance bottlenecks caused by re-renders and layout thrashing.

Learn more in our documentation:
[`Cursors`](/docs/api-reference/liveblocks-react-ui#Cursors).

### &lt;Cursor /&gt; [#cursor]

Displays a styled multiplayer cursor, helpful for building custom realtime
cursors with [`useOthers`](/docs/api-reference/liveblocks-react#useOthers).

<PreBuiltComponentCursor />

#### Features

- Customizable background color and label.
- Text color is automatically adjusted to contrast with the background color.
- Has a height and width of `0px` making it easy to position accurately.

Learn more in our documentation:
[`Cursor`](/docs/api-reference/liveblocks-react-ui#Cursor).

### &lt;CommentPin /&gt; [#comment-pin]

Displays a comment pin that can be used anywhere in your UI, or as a trigger to
open pop-up threads.

<PreBuiltComponentCommentPin />

#### Features

- Displays an avatar inside the pin when `userId` is provided.
- Define which corner the pin should point to, such as `"top-left"`.
- Can be used as a trigger for [`FloatingComposer`](#floating-composer) and
  [`FloatingThread`](#floating-thread).

### &lt;FloatingComposer /&gt; [#floating-composer]

Displays a floating thread composer alongside a trigger element, such as a
button. Clicking the trigger opens the composer, and clicking outside closes it.

<PreBuiltComponentFloatingComposer />

#### Features

- Use any React component as a trigger or opt for our pre-built
  [`CommentPin`](#comment-pin).
- Define positioning, offset, and alignment relative to the trigger.
- Combine with [`FloatingThread`](#floating-thread) to display the created
  thread.

Learn more in our documentation:
[`FloatingComposer`](/docs/api-reference/liveblocks-react-ui#FloatingComposer).

### &lt;FloatingThread /&gt; [#floating-thread]

Displays a floating comment thread alongside a trigger element, such as a
button. Clicking the trigger opens the thread, and clicking outside closes it.

<PreBuiltComponentFloatingThread />

#### Features

- Use any React component as a trigger or opt for our pre-built
  [`CommentPin`](#comment-pin).
- Define positioning, offset, and alignment relative to the trigger.
- Combine with [`FloatingComposer`](#floating-composer) to display a composer to
  create a thread.

Learn more in our documentation:
[`FloatingThread`](/docs/api-reference/liveblocks-react-ui#FloatingThread).

## Use cases

### Draggable comments

Using [`FloatingThread`](#floating-thread) and [`CommentPin`](#comment-pin)
together, you can create a canvas-like UI with draggable comment pins, like in
the live demo below.

<Figure
  caption={
    <>
      Our{" "}
      <Link href="/examples/canvas-comments/nextjs-comments-canvas">
        Next.js Canvas Comments
      </Link>{" "}
      example
    </>
  }
>
  <Embed
    src="https://nextjs-comments-canvas.liveblocks.app"
    className="aspect-16/10 w-full bg-white"
  />
</Figure>

This works by taking `x` and `y` coordinates for each thread, storing them on
thread metadata, and then using them to position the comment pin. `CommentPin`
works as the trigger for each `FloatingThread`.

```tsx
function DraggableComments() {
  const { threads } = useThreads();

  return threads.map((thread) => (
    // +++
    <FloatingThread key={thread.id} thread={thread}>
      <CommentPin
        userId={thread.comments[0]?.userId}
        style={{
          position: "absolute",
          left: thread.metadata.x,
          top: thread.metadata.y,
        }}
      />
    </FloatingThread>
    // +++
  ));
}
```

Learn how to
[get started with draggable comments in Next.js](/docs/get-started/nextjs-comments-canvas).

### Table comments

By adding [`FloatingComposer`](#floating-composer) and
[`FloatingThread`](#floating-thread) to a table you can enable users to leave
comments on individual cells.

<Figure
  caption={
    <>
      Our{" "}
      <Link href="/examples/ag-grid-comments/nextjs-comments-ag-grid">
        Next.js Comments AG Grid
      </Link>{" "}
      example
    </>
  }
>
  <Embed
    src="https://nextjs-comments-ag-grid.liveblocks.app"
    className="aspect-16/10 w-full bg-white"
    zoom={0.8}
  />
</Figure>

Each cell is passed a `rowId` and `columnId` which is used in thread metadata to
render comments attached the cell using `FloatingThread`. If a thread isn’t
found for the cell, then `FloatingComposer` is displayed, allowing the user to
create a new thread with this metadata.

```tsx
function TableCellComment({ threads, rowId, columnId }) {
  const thread = threads.find(
    ({ metadata }) => metadata.rowId === rowId && metadata.columnId === columnId
  );

  if (!thread) {
    return (
      // +++
      <FloatingComposer metadata={{ rowId, columnId }}>
        <button>➕ Add comment</button>
      </FloatingComposer>
      // +++
    );
  }

  return (
    // +++
    <FloatingThread thread={thread}>
      <img src={thread.comments[0]?.userId} alt="User avatar" />
    </FloatingThread>
    // +++
  );
}
```

Learn how to get started with commenting in
[HTML tables](/docs/get-started/nextjs-comments-table) and
[AG Grid](/docs/get-started/nextjs-comments-ag-grid).

### Presence

Using [`AvatarStack`](#avatar-stack) and [`Cursors`](#cursors) together, you can
create real live presence in your product.

<Figure
  caption={
    <>
      Our{" "}
      <Link href="/examples/live-avatar-stack/nextjs-live-avatars">
        Next.js Live Avatars
      </Link>{" "}
      example.
    </>
  }
>
  <Embed
    src="https://nextjs-live-avatars.liveblocks.app"
    className="aspect-16/10 w-full bg-white"
  />
</Figure>

This works by setting up user authentication then simply importing the
components, wrapping your main content within `Cursors`.

```tsx highlight="6,9"
function Layout({ children }) {
  return (
    <div>
      <header>
        Untitled document
        <AvatarStack max={3} size={32} />
      </header>
      <main>
        <Cursors>{children}</Cursors>
      </main>
    </div>
  );
}
```

Learn how to
[get started with presence in Next.js](/docs/get-started/nextjs-presence).

## Upgrade

To use the latest features, update your packages with the following command.

```bash
npx liveblocks upgrade
```

If you were previously on Liveblocks 3.10 or below, make sure to follow our
[upgrade guides](/docs/platform/upgrading) before updating.

## Contributors

<Contributors gitHubUsernames={["marcbouchenoire", "ctnicholas"]} />