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

# React

> Mount @commentify/react in Blade or Inertia. Same thread as Livewire, including markdown, reports, and dark mode.

The installer writes `resources/js/components/CommentThread.tsx`, publishes the SDK, and wires `package.json`. Finish with React, the Vite plugin, and the [JavaScript](/javascript) Vite notes (`exclude` + `@viteReactRefresh`).

## Scaffolded wrapper

```tsx theme={null}
// resources/js/components/CommentThread.tsx
import { CommentThread as CommentifyThread } from "@commentify/react";

export default function CommentThread({ type, id }) {
  return <CommentifyThread type={type} id={id} loginUrl="/login" />;
}
```

Keeping the markup in the package is what lets Blade and JS stay in step.

### Props

| Prop                 | Purpose                                                |
| -------------------- | ------------------------------------------------------ |
| `type`               | Commentable **alias** (`articles`), not a class name   |
| `id`                 | Commentable primary key                                |
| `sort`               | `newest` \| `oldest` \| `most_liked` \| `most_replied` |
| `perPage`            | Page size (API caps at 50)                             |
| `loginUrl`           | Guest login link                                       |
| `token`              | Bearer token (skips cookies)                           |
| `baseUrl` / `prefix` | Override API location                                  |
| `client`             | Reuse a `CommentifyClient`                             |
| `ui`                 | Pass UI config yourself to skip `GET ui`               |
| `onError`            | `(error: ApiError) => void`                            |

`type` and `id` also exist on `CommentifyClient` methods as the first arguments to `listComments` / `createComment`.

## Mount in a Blade view

Pass the thread identity through data attributes so the same bundle works on every page:

```blade theme={null}
{{-- resources/views/articles/show.blade.php --}}
<div id="comments" data-type="articles" data-id="{{ $article->id }}"></div>

@viteReactRefresh
@vite('resources/js/comments.tsx')
```

```tsx theme={null}
// resources/js/comments.tsx
import { createRoot } from "react-dom/client";
import CommentThread from "./components/CommentThread";

const el = document.getElementById("comments");

if (el) {
  createRoot(el).render(
    <CommentThread type={el.dataset.type!} id={Number(el.dataset.id)} />
  );
}
```

`articles` is the alias from `commentables`.

## Mount in an Inertia page

It is an ordinary component:

```tsx theme={null}
// resources/js/Pages/Articles/Show.tsx
import CommentThread from "@/components/CommentThread";

export default function Show({ article }) {
  return (
    <article>
      <h1>{article.title}</h1>
      <CommentThread type="articles" id={article.id} />
    </article>
  );
}
```

## Share one client

Wrap the app in `CommentifyProvider` once (for example in Inertia `app.tsx`):

```tsx theme={null}
import { CommentifyClient } from "@commentify/core";
import { CommentifyProvider } from "@commentify/react";

<CommentifyProvider client={new CommentifyClient({ token })}>
  <App />
</CommentifyProvider>
```

`<CommentThread />` and `useCommentThread()` pick it up. Passing `baseUrl`, `prefix`, or `token` on a thread overrides the provider for that thread only.

## Headless

When you want the data and none of the markup, use [the hook](/hooks) and [headless API](/headless).
