This July we released improvements to different facets of all our products.

- [Dashboard improvements](#dashboard-improvements): Search, sort, and delete
  rooms from our website.
- [Text editor components](#text-editor-components): Easily render floating
  comment threads like in Notion.
- [Resolved thread changes](#resolved-thread-changes): No longer a custom
  feature, new hooks & more.
- [Custom links in Comments](#custom-links-in-comments): Better rich-text
  support, create custom links.
- [Delete inbox notifications](#delete-inbox-notifications): Now possible with
  hooks, methods, REST APIs.
- [Vanilla JavaScript support](#vanilla-javascript-support): Use Comments &
  Notifications in any framework.
- [Storage sync badge](#storage-sync-badge): A new option to create smoother
  Storage status UI.

## Upgrade now

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

```bash
npx create-liveblocks-app@latest --upgrade
```

If you were previously on Liveblocks 2.1 or below, make sure to follow our
latest [upgrade guide](/docs/platform/upgrading/2.2) as there are breaking
changes.

## Dashboard improvements [#dashboard-improvements]

We’ve made a number of improvements to our [dashboard](/dashboard), specifically
to the rooms page. You can now search for rooms by their ID, sort them in
various ways, and check how many users are currently connected to each room.

<Figure>
  <video autoPlay loop muted playsInline>
    <source
      src="/images/blog/whats-new-in-liveblocks-july-24/search-sort-rooms.mp4"
      type="video/mp4"
    />
  </video>
</Figure>

We’ve also made it possible to delete rooms directly from the dashboard.

<Figure>
  <Image
    src="/images/blog/whats-new-in-liveblocks-july-24/delete-room.png"
    alt=""
    width={672}
    height={378}
    quality={90}
  />
</Figure>

We’re investing more into our dashboard, and we’ll have an update with further
improvements next month.

## Text editor components [#text-editor-components]

We’ve added support for rendering Notion-like floating threads in
[Text Editor](/text-editor). This is a difficult feature to implement from
scratch, but it’s now just a couple of lines of code with Liveblocks. We’ve
created two different components that present threads in different ways.

### Anchored Threads

[`AnchoredThreads`](/docs/api-reference/liveblocks-react-lexical#AnchoredThreads)
displays your threads in a sidebar, positioning each alongside the text
highlight it references. Threads never overlap, always stack in the correct
order, and move next to the highlight when selected.

<Figure>
  <video autoPlay loop muted playsInline>
    <source
      src="/images/blog/whats-new-in-liveblocks-july-24/anchored-threads.mp4"
      type="video/mp4"
    />
  </video>
</Figure>

Anchored threads work especially well on large screens.

### Floating Threads

[`FloatingThreads`](/docs/api-reference/liveblocks-react-lexical#FloatingThreads)
displays each thread below its text highlight. Floating threads automatically
flip above the highlight when they’re too close to the bottom of the screen.

<Figure>
  <video autoPlay loop muted playsInline>
    <source
      src="/images/blog/whats-new-in-liveblocks-july-24/floating-threads.mp4"
      type="video/mp4"
    />
  </video>
</Figure>

Floating threads work especially well on small screens.

### Use them in combination

We generally recommend using both components in your text editor, showing
floating threads on mobile, and anchored threads on desktop. Below we’re
implementing this using Tailwind CSS, along with filtering out any resolved
threads.

```tsx
function ThreadOverlay() {
  const { threads } = useThreads({ query: { resolved: false } });

  return (
    <>
      <FloatingThreads
        threads={threads}
        className="block w-[350px] md:hidden"
      />
      <AnchoredThreads
        threads={threads}
        className="hidden w-[350px] sm:block"
      />
    </>
  );
}
```

Add your new component into your Lexical editor to use it.

```tsx highlight="3"
<LexicalComposer initialConfig={initialConfig}>
  <LiveblocksPlugin>
    <ThreadOverlay />
  </LiveblocksPlugin>
  <RichTextPlugin contentEditable={<ContentEditable />} />
</LexicalComposer>
```

## Resolved thread changes [#resolved-thread-changes]

We’ve added a number of new ways to use resolved threads in
[Comments](/comments). Previously, resolving a thread was a custom metadata
feature, but it now has first-class support, meaning we provide hooks, methods,
and REST APIs for using it. It’s also become part of the thread object.

```js highlight="4"
{
  type: "thread",
  id: "th_sf8s6sh...",
  resolved: false,
  // ...
}
```

Below we’re creating a simple button that toggles the resolved status of a
thread using the two new resolved hooks.

```tsx
function ToggleResolve({ thread }) {
  const resolve = useMarkThreadAsResolved();
  const unresolve = useMarkThreadAsUnresolved();

  if (thread.resolved) {
    return <button onClick={() => unresolve(thread.id)}>Unresolve</button>;
  }

  return <button onClick={() => resolved(thread.id)}>Resolve</button>;
}
```

For more information on the new hooks, learn more in our API reference:

- [`useMarkThreadAsResolved`](/docs/api-reference/liveblocks-node#post-rooms-roomId-threads-threadId-mark-as-resolved)
- [`useMarkThreadAsUnresolved`](/docs/api-reference/liveblocks-node#post-rooms-roomId-threads-threadId-mark-as-unresolved)

We also have equivalent methods on the server:

- [`liveblocks.deleteInboxNotification`](/docs/api-reference/liveblocks-node#delete-users-userId-inboxNotifications-inboxNotificationId)
- [`liveblocks.deleteAllInboxNotifications`](/docs/api-reference/liveblocks-node#delete-users-userId-inboxNotifications)

## Custom links in Comments [#custom-links-in-comments]

Comments now allows you to create links with custom text by making selection and
pasting in your URL.

<Figure>
  <video autoPlay loop muted playsInline>
    <source
      src="/images/blog/whats-new-in-liveblocks-july-24/paste-link.mp4"
      type="video/mp4"
    />
  </video>
</Figure>

You can also now paste rich-text content into comments, and its format will be
preserved. Get started with a [Comments example](/examples/browse/comments) to
try this.

## Delete inbox notifications [#delete-inbox-notifications]

Deleting inbox notifications is now possible using new hooks, methods, REST
APIs, and directly in our notification components. You can see this below in our
[Comments Notifications example](/examples/comments-notifications/nextjs-comments-notifications).

<Figure>
  <video autoPlay loop muted playsInline>
    <source
      src="/images/blog/whats-new-in-liveblocks-july-24/delete-notifications.mp4"
      type="video/mp4"
    />
  </video>
</Figure>

Here’s how to create a button that deletes all notifications for the current
user.

```tsx
function DeleteButton() {
  const deleteAll = useDeleteAllInboxNotifications();

  return <button onClick={deleteAll}>🗑️ Delete all</button>;
}
```

For more information on the new hooks, learn more in our API reference:

- [`useDeleteInboxNotification`](/docs/api-reference/liveblocks-react#useDeleteInboxNotification)
- [`useDeleteAllInboxNotifications`](/docs/api-reference/liveblocks-react#useDeleteAllInboxNotifications)

We also have equivalent methods on the server:

- [`liveblocks.deleteInboxNotification`](/docs/api-reference/liveblocks-node#delete-users-userId-inboxNotifications-inboxNotificationId)
- [`liveblocks.deleteAllInboxNotifications`](/docs/api-reference/liveblocks-node#delete-users-userId-inboxNotifications)

## Vanilla JavaScript support [#vanilla-javascript-support]

[Comments](/comments) and [Notifications](/notifications) are now available to
use in vanilla JavaScript. Previously, these products were only supported
through our React packages, but now a set of methods has been exposed enabling
use in regular JavaScript.

```ts
// Fetch all threads
const { threads } = await room.getThreads();

// Add a reaction to a comment
const reaction = await room.addReaction({
  threadId: "th_xxx",
  commentId: "cm_xxx",
  emoji: "✅",
});

// Fetch recent notifications
const { inboxNotifications } = await client.getInboxNotificationsSince({
  since: new Date("2024-08-06"),
});
```

You can use these methods in any JavaScript framework, for example Angular,
Svelte, or Vue as shown below.

```html highlight="8-9"
<script setup>
  import { ref, onMounted } from "vue";
  import { room } from "./room";

  const threadList = ref([]);

  onMounted(async () => {
    const { threads } = await room.getThreads();
    threadList.value = threads;
  });
</script>

<template>
  <div v-for="thread in threadList" :key="thread.id">
    <Avatar :userId="thread.comments[0].userId" />
    {{ stringifyCommentBody(thread.comments[0].body) }}
    <a :href="...">View replies</a>
  </div>
</template>
```

## Storage sync badge [#storage-sync-badge]

Last month we made it easy to display a synchronizing/saved badge in your
application with our new
[`useStorageStatus`](/docs/api-reference/liveblocks-react#useStorageStatus)
hook, which lets you know if local Storage changes have been synchronized with
our servers or not.

```tsx highlight="2"
// "synchronizing" | "synchronized"
const storageStatus = useStorageStatus();
```

However, because Storage often synchronizes in less than 50ms, this often
results in a component that flickers in a distracting manner. We’ve added a new
option to smooth out changes to prevent this happening. We’re using this option
below to render a badge in our
[collaborative spreadsheet example](/examples/collaborative-spreadsheet-advanced/nextjs-spreadsheet-advanced).

<Figure>
  <video autoPlay loop muted playsInline>
    <source
      src="/images/blog/whats-new-in-liveblocks-july-24/storage-status.mp4"
      type="video/mp4"
    />
  </video>
</Figure>

We’ve implemented this by passing the `smooth` option to the hook.

```tsx highlight="2"
function StorageStatusBadge() {
  const storageStatus = useStorageStatus({ smooth: true });

  return (
    <div>{storageStatus === "synchronized" ? "✅ Saved" : "🔄 Saving"}</div>
  );
}
```

## Upgrade

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

```bash
npx create-liveblocks-app@latest --upgrade
```

If you were previously on Liveblocks 2.1 or below, make sure to follow our
latest [upgrade guide](/docs/platform/upgrading/2.2) as there are breaking
changes.

## More information

This post is a summary of July’s changes, make sure to read our
[Changelog](/changelog) to learn about every change we’ve made, no matter how
minor.

## Contributors

<Contributors
  gitHubUsernames={[
    "guillaumesalles",
    "ctnicholas",
    "sugardarius",
    "pierrelevaillant",
    "nimeshnayaju",
    "ofoucherot",
    "nvie",
    "marcbouchenoire",
    "dant2021",
    "jrowny",
    "flowflorent",
    "teddarific",
    "stevenfabre",
  ]}
/>