Floating Threads

Leave a comment and start a conversation anywhere on a page


Click the button above to enter annotation mode.
Then click anywhere on the page!

Live Demo

When to use

The Floating Threads component allows you to leave a comment anywhere on the page. Think of it like the comment mode in Figma, for example. It not only provides you with a button to start commenting, but also renders all of your existing threads on that page.

This component renders a single button. Clicking on it will enter the comment mode, which allows users to click anywhere on the page to add a comment which will stick to that particular element on the page. After clicking, a composer will appear right next to where the user clicked, allowing them type a message. You can retrieve and reply to an existing comment by clicking on the pins on the page.

For the best experience with Floating Threads, we recommend using the Annotations API. This ensures that your users' messages appear in the right place, even if other things change on the page. Without using this API, you may find that pins disappear.

This component pairs well with:


How to use

import { FloatingThreads } from "@cord-sdk/react";

export const Example = () => {
  return (
    <FloatingThreads location={{ "page": "index" }} />
  );
};
Copy

Properties


location

optional
string
The location concept for the floating threads component. It indicates which floating threads will be rendered on a page, as well as what the location value of the new floating threads created from that button will be.
If unset, this field will default to the current URL for the page.

showButton

optional
boolean
Whether to show the "add comment" button or not.

buttonLabel

optional
string
The text label on the button. If set to an empty string, the button will not have a label.
If unset, this value defaults to the string Add comment.

iconUrl

optional
string
format: url
If provided, changes the URL of the icon. If set to an empty string or omitted, the button will get the default comment icon.

threadName

optional
string
Sets the name of the thread. The thread name is used in a small number of places where a short name or header is useful to distinguish the thread; the default value is nearly always fine. A newly-created thread will have its title set to this value, but the title of an existing thread will not be changed.
If this value is not provided, the title of the current page (document.title) will be used as a default value.

showScreenshotPreview

optional
boolean
Toggles whether screenshot previews are shown in the first message of a Floating Thread. The default setting is set to false.

onStart

optional
function
A callback that will be fired when once the page is in comment mode.

onFinish

optional
function
A callback that will be fired when you leave comment mode with at least one message sent.

onCancel

optional
function
A callback that will be fired when the thread is closed before any message is added.

Methods


openThread

optional
function
This method on the <FloatingThreads /> component can be used to programmatically open a particular thread.
This function takes one argument, which is an identifier for a thread.
You can use this method by getting a reference to the underlying <cord-floating-threads> DOM element:
import { useCallback, useRef } from "react";

import {
  CordProvider,
  FloatingThreads,
  ThreadList,
} from "@cord-sdk/react";

const App = () => {
  const floatingThreadsRef = useRef(null);
  const onThreadClickCallback = useCallback(
    (threadID: string, threadSummary: ThreadSummary) => {
      if (!floatingThreadsRef.current) {
        return;
      }

      floatingThreadsRef.current.openThread(threadID);
    },
    []
  );

  return (
    <CordProvider clientAuthToken={cordToken}>
      <ThreadList location={{ page: 'foo' }} onThreadClick={onThreadClickCallback} />
      <FloatingThreads location={{ page: 'foo'}} ref={floatingThreadsRef}>
    </CordProvider>
  );
}

CSS Variables

These can be used to customize the component. You can learn more about customization here.

Note: These variables all apply to the default button used to create new floating threads - not to the threads themselves.

To style the actual thread elements, including the message composer, refer to the Thread CSS variables.

To style the pins which mark where threads have been placed, refer to the Annotations CSS variables.

Name Default Value
--cord-floating-threads-font-size
var(--cord-font-size-body, 14px);
--cord-floating-threads-line-height
var(--cord-line-height-body, var(--cord-space-l, 20px));
--cord-floating-threads-letter-spacing
normal;
--cord-floating-threads-text-color
var(--cord-secondary-button-content-color, var(--cord-color-content-emphasis, #121314));
--cord-floating-threads-text-color--hover
var(--cord-secondary-button-content-color--hover, var(--cord-color-content-emphasis, #121314));
--cord-floating-threads-text-color--active
var(--cord-secondary-button-content-color--active, var(--cord-color-base, #FFFFFF));
--cord-floating-threads-text-color--disabled
var(--cord-secondary-button-content-color--disabled, var(--cord-color-content-secondary, #97979F));
--cord-floating-threads-background-color
var(--cord-secondary-button-background-color, var(--cord-color-base-strong, #F6F6F6));
--cord-floating-threads-background-color--hover
var(--cord-secondary-button-background-color--hover, var(--cord-color-base-x-strong, #DADCE0));
--cord-floating-threads-background-color--active
var(--cord-secondary-button-background-color--active, var(--cord-color-brand-primary, #121314));
--cord-floating-threads-background-color--disabled
var(--cord-secondary-button-background-color--disabled, var(--cord-color-base-strong, #F6F6F6));
--cord-floating-threads-padding
6px 8px;
--cord-floating-threads-height
var(--cord-button-height-auto, auto);
--cord-floating-threads-gap
var(--cord-space-3xs, 4px);
--cord-floating-threads-border
var(--cord-button-border-none, none);
--cord-floating-threads-icon-size
var(--cord-space-l, 20px);
--cord-thread-background-color
var(--cord-color-base, #FFFFFF);
--cord-thread-border
1px solid var(--cord-color-base-x-strong, #DADCE0);
--cord-thread-border-top
var(--cord-thread-border, 1px solid var(--cord-color-base-x-strong, #DADCE0));
--cord-thread-border-right
var(--cord-thread-border, 1px solid var(--cord-color-base-x-strong, #DADCE0));
--cord-thread-border-bottom
var(--cord-thread-border, 1px solid var(--cord-color-base-x-strong, #DADCE0));
--cord-thread-border-left
var(--cord-thread-border, 1px solid var(--cord-color-base-x-strong, #DADCE0));
--cord-thread-border-radius
var(--cord-border-radius-medium, var(--cord-space-3xs, 4px));
--cord-thread-padding
0px;
--cord-thread-send-button-font-size
var(--cord-font-size-body, 14px);
--cord-thread-send-button-text-color
var(--cord-primary-button-content-color, var(--cord-color-base, #FFFFFF));
--cord-thread-send-button-text-color--hover
var(--cord-primary-button-content-color--hover, var(--cord-color-base, #FFFFFF));
--cord-thread-send-button-text-color--active
var(--cord-primary-button-content-color--active, var(--cord-color-base-x-strong, #DADCE0));
--cord-thread-send-button-text-color--disabled
var(--cord-primary-button-content-color--disabled, var(--cord-color-base, #FFFFFF));
--cord-thread-send-button-background-color
var(--cord-primary-button-background-color, var(--cord-color-brand-primary, #121314));
--cord-thread-send-button-background-color--hover
var(--cord-primary-button-background-color--hover, var(--cord-color-brand-primary, #121314));
--cord-thread-send-button-background-color--active
var(--cord-primary-button-background-color--active, var(--cord-color-brand-primary, #121314));
--cord-thread-send-button-background-color--disabled
var(--cord-primary-button-background-color--disabled, var(--cord-color-content-secondary, #97979F));
--cord-thread-send-button-padding
var(--cord-space-2xs, 8px);
--cord-thread-height
auto;
--cord-thread-max-height
none;
--cord-thread-width
auto;