> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sublay.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Quick Start

> Get comment components running in under 5 minutes

export const AddCommandBuilder = ({component: initialComponent = "comments-threaded"}) => {
  const components = [{
    value: "comments-threaded",
    label: "Threaded comments",
    translated: true
  }, {
    value: "comments-social",
    label: "Social comments",
    translated: true
  }, {
    value: "notifications-control",
    label: "Notifications",
    translated: false
  }];
  const languages = [{
    value: "en",
    label: "English"
  }, {
    value: "ar",
    label: "Arabic — العربية"
  }, {
    value: "zh",
    label: "Chinese (Simplified) — 简体中文"
  }, {
    value: "nl",
    label: "Dutch — Nederlands"
  }, {
    value: "fr",
    label: "French — Français"
  }, {
    value: "de",
    label: "German — Deutsch"
  }, {
    value: "he",
    label: "Hebrew — עברית"
  }, {
    value: "hi",
    label: "Hindi — हिन्दी"
  }, {
    value: "id",
    label: "Indonesian — Bahasa Indonesia"
  }, {
    value: "it",
    label: "Italian — Italiano"
  }, {
    value: "ja",
    label: "Japanese — 日本語"
  }, {
    value: "ko",
    label: "Korean — 한국어"
  }, {
    value: "pl",
    label: "Polish — Polski"
  }, {
    value: "pt",
    label: "Portuguese — Português"
  }, {
    value: "ru",
    label: "Russian — Русский"
  }, {
    value: "es",
    label: "Spanish — Español"
  }, {
    value: "tr",
    label: "Turkish — Türkçe"
  }];
  const [component, setComponent] = useState(initialComponent);
  const [language, setLanguage] = useState("en");
  const [copied, setCopied] = useState(false);
  const translated = components.find(c => c.value === component)?.translated;
  const lang = translated ? language : "en";
  const command = `npx @sublay/cli add ${component} --ref v8${lang === "en" ? "" : ` --lang ${lang}`}`;
  const copy = () => {
    navigator.clipboard?.writeText(command).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 1500);
    });
  };
  const fieldClass = "mt-1 w-full rounded-lg border border-zinc-200 bg-white px-3 py-2 text-sm text-zinc-900 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-100";
  const labelClass = "text-sm font-medium text-zinc-700 dark:text-zinc-300";
  return <div className="not-prose my-6 rounded-xl border border-zinc-200 p-4 dark:border-zinc-800">
      <div className="grid gap-4 sm:grid-cols-2">
        <label className={labelClass}>
          Component
          <select className={fieldClass} value={component} onChange={e => setComponent(e.target.value)}>
            {components.map(c => <option key={c.value} value={c.value}>
                {c.label}
              </option>)}
          </select>
        </label>
        <label className={labelClass}>
          Language
          <select className={fieldClass} value={lang} disabled={!translated} onChange={e => setLanguage(e.target.value)}>
            {languages.map(l => <option key={l.value} value={l.value}>
                {l.label}
              </option>)}
          </select>
        </label>
      </div>

      <div className="mt-4 flex items-center gap-3 rounded-lg bg-zinc-950 px-4 py-3">
        {}
        <span dir="ltr" className="min-w-0 flex-1 break-words font-mono text-sm text-zinc-100">
          {command}
        </span>
        <button type="button" onClick={copy} className="shrink-0 rounded-md border border-zinc-700 px-3 py-1 text-xs font-medium text-zinc-200 hover:bg-zinc-800">
          {copied ? "Copied" : "Copy"}
        </button>
      </div>

      <p className="mt-3 text-xs text-zinc-500 dark:text-zinc-400">
        The platform (React, React Native or Expo) and the style (styled or
        Tailwind) come from your <code>sublay.json</code>, written by{" "}
        <code>npx @sublay/cli init</code>.
      </p>
    </div>;
};

# Quick Start Guide

This guide will have you up and running with Sublay comment components in under 5 minutes.

***

## Before You Begin

* ✅ Node.js 20.5+ installed
* ✅ A React, React Native, or Expo project
* ✅ A [Sublay project](https://dash.sublay.io) created

***

## Step 1: Initialize the CLI

Run the init command in your project directory:

```bash theme={null}
cd your-project
npx @sublay/cli init
```

### Answer the prompts:

<Steps>
  <Step title="Select Platform">
    ```
    ? Which platform are you using?
    ❯ React (Web)
      React Native
      Expo
    ```
  </Step>

  <Step title="Choose Styling">
    ```
    ? Which styling approach do you prefer?
    ❯ Tailwind CSS
      Inline Styles
    ```

    * Select **Tailwind CSS** if you use Tailwind
    * Select **Inline Styles** otherwise
  </Step>

  <Step title="Set Component Path">
    ```
    ? Where should components be installed? (src/components)
    ```

    Press Enter to use the default, or type a custom path.
  </Step>
</Steps>

The CLI creates a `sublay.json` configuration file and checks for required dependencies.

***

## Step 2: Install Dependencies (if needed)

<Tabs>
  <Tab title="React (Web)">
    ```bash theme={null}
    npm install @sublay/react-js
    ```
  </Tab>

  <Tab title="React Native">
    ```bash theme={null}
    npm install @sublay/react-native
    ```
  </Tab>

  <Tab title="Expo">
    ```bash theme={null}
    npm install @sublay/expo
    ```
  </Tab>
</Tabs>

<Info>
  The CLI will prompt you to install these automatically if they're missing.
</Info>

***

## Step 3: Add a Component

Pick a component and a language to get the command:

<AddCommandBuilder />

* **Threaded comments** — Reddit-style discussions with unlimited nesting, upvote/downvote, threading lines, and collapsible threads.
* **Social comments** — Instagram-style comments with single-level nesting, heart/like system, and Top/New/Old sorting.
* **Notifications** — a notification bell with a dropdown of the user's notifications.

The language applies to the comment components; see [Languages & Right-to-Left](/v8/components/customization/languages-rtl).

`--ref v8` reads the component from the `v8` branch of the registry, where the v8 components live.

The CLI copies about 40 source files into your project and shows a usage example. It also checks your `package.json` for the third-party packages the component needs (the Giphy packages for the GIF picker, for example) and offers to install the ones that are missing.

***

## Step 4: Set Up SublayProvider

Wrap your app (or the relevant section) with `SublayProvider`:

<Tabs>
  <Tab title="React (Web)">
    ```tsx theme={null}
    // App.tsx
    import { SublayProvider } from '@sublay/react-js';

    function App() {
      return (
        <SublayProvider
          projectId="your-project-id"
          signedToken={yourAuthToken}
        >
          {/* Your app content */}
        </SublayProvider>
      );
    }
    ```
  </Tab>

  <Tab title="React Native / Expo">
    ```tsx theme={null}
    // App.tsx
    import { SublayProvider } from '@sublay/react-native'; // or '@sublay/expo'

    function App() {
      return (
        <SublayProvider
          projectId="your-project-id"
          signedToken={yourAuthToken}
        >
          {/* Your app content */}
        </SublayProvider>
      );
    }
    ```
  </Tab>
</Tabs>

<Note>
  For authentication setup and obtaining `signedToken`, see the [Authentication](/v8/authentication) guide.
</Note>

***

## Step 5: Use the Component

<Tabs>
  <Tab title="Threaded Comments">
    ```tsx theme={null}
    // BlogPost.tsx
    import { ThreadedCommentSection } from './components/comments-threaded';

    function BlogPost({ post }) {
      return (
        <div>
          <h1>{post.title}</h1>
          <p>{post.content}</p>
          <ThreadedCommentSection foreignId={post.id} createIfNotFound />
        </div>
      );
    }
    ```
  </Tab>

  <Tab title="Social Comments">
    ```tsx theme={null}
    // Post.tsx
    import { SocialCommentSection } from './components/comments-social';

    function Post({ post }) {
      return (
        <div>
          <img src={post.image} />
          <p>{post.caption}</p>
          <SocialCommentSection foreignId={post.id} createIfNotFound />
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

That's it! You now have a fully functional comment system.

***

## Complete Example

<Tabs>
  <Tab title="Threaded Comments">
    ```tsx theme={null}
    import { useEffect, useState } from 'react';
    import { SublayProvider, useSignTestingJwt } from '@sublay/react-js';
    import { ThreadedCommentSection } from './components/comments-threaded';

    const PROJECT_ID = import.meta.env.VITE_PUBLIC_SUBLAY_PROJECT_ID;
    const PRIVATE_KEY = import.meta.env.VITE_PUBLIC_SUBLAY_SECRET_KEY;

    const DUMMY_USER = { id: 'user1', username: 'tech_developer' };

    function App() {
      const signTestingJwt = useSignTestingJwt();
      const [signedToken, setSignedToken] = useState<string>();

      useEffect(() => {
        const handleSignJwt = async () => {
          const token = await signTestingJwt({
            projectId: PROJECT_ID,
            privateKey: PRIVATE_KEY,
            payload: DUMMY_USER,
          });
          setSignedToken(token);
        };
        handleSignJwt();
      }, []);

      return (
        <SublayProvider projectId={PROJECT_ID} signedToken={signedToken}>
          <div className="max-w-4xl mx-auto p-8">
            <h1>My Blog Post</h1>
            <p>This is my awesome blog post content...</p>
            <ThreadedCommentSection foreignId="blog-post-123" createIfNotFound />
          </div>
        </SublayProvider>
      );
    }

    export default App;
    ```
  </Tab>

  <Tab title="Social Comments">
    ```tsx theme={null}
    import { useEffect, useState } from 'react';
    import { SublayProvider, useSignTestingJwt } from '@sublay/react-js';
    import { SocialCommentSection } from './components/comments-social';

    const PROJECT_ID = import.meta.env.VITE_PUBLIC_SUBLAY_PROJECT_ID;
    const PRIVATE_KEY = import.meta.env.VITE_PUBLIC_SUBLAY_SECRET_KEY;

    const DUMMY_USER = { id: 'user1', username: 'social_user' };

    function App() {
      const signTestingJwt = useSignTestingJwt();
      const [signedToken, setSignedToken] = useState<string>();

      useEffect(() => {
        const handleSignJwt = async () => {
          const token = await signTestingJwt({
            projectId: PROJECT_ID,
            privateKey: PRIVATE_KEY,
            payload: DUMMY_USER,
          });
          setSignedToken(token);
        };
        handleSignJwt();
      }, []);

      return (
        <SublayProvider projectId={PROJECT_ID} signedToken={signedToken}>
          <div className="max-w-2xl mx-auto p-8">
            <img src="post.jpg" className="w-full rounded-lg" />
            <p className="mt-4">Check out this amazing photo!</p>
            <SocialCommentSection foreignId="post-456" createIfNotFound />
          </div>
        </SublayProvider>
      );
    }

    export default App;
    ```
  </Tab>
</Tabs>

***

## What Gets Installed

```
src/components/comments-threaded/
├── index.ts
├── components/          # 22 UI component files
│   ├── threaded-comment-section.tsx
│   ├── new-comment-form.tsx
│   ├── comments-feed/
│   └── modals/
├── hooks/
├── utils/
├── context/
└── shared/              # Shared pieces: GIF picker, avatar, skeletons, icons
```

All files are editable TypeScript/TSX, documented with inline comments, and committed to your repo. That includes the files in `shared/`, the presentational pieces the component is built from.

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="Import errors after adding component" icon="triangle-exclamation">
    Make sure the import path matches your `paths.components` in `sublay.json`:

    ```tsx theme={null}
    // paths.components = "src/components"
    import { ThreadedCommentSection } from './components/comments-threaded';

    // paths.components = "app/ui"
    import { ThreadedCommentSection } from './ui/comments-threaded';
    ```
  </Accordion>

  <Accordion title="Components not rendering" icon="eye-slash">
    1. Check that `<SublayProvider>` wraps the component
    2. Verify `projectId` and `signedToken` are correctly set
    3. Check the browser console for errors
  </Accordion>

  <Accordion title="TypeScript errors" icon="code">
    Ensure your `tsconfig.json` includes the components directory:

    ```json theme={null}
    { "include": ["src/**/*"] }
    ```
  </Accordion>

  <Accordion title="Dark mode not working (Tailwind)" icon="moon">
    Set `darkMode: 'class'` in `tailwind.config.js` and add a `dark` class to a parent element:

    ```tsx theme={null}
    <html className={isDark ? 'dark' : ''}>
    ```
  </Accordion>
</AccordionGroup>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Props API" icon="sliders" href="/v8/components/components/threaded/props-api">
    Learn about available props and options
  </Card>

  <Card title="File Structure" icon="folder-tree" href="/v8/components/components/threaded/file-structure">
    Understand the installed file organization
  </Card>

  <Card title="Customization" icon="paintbrush" href="/v8/components/customization/overview">
    Customize colors, layout, and functionality
  </Card>

  <Card title="Styling Variants" icon="palette" href="/v8/components/customization/styling-variants">
    Inline styles vs Tailwind CSS
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.