# React Setup (https://v1.s3.dimah.dev/docs/react/setup)

## Install [#install]

```npm
npm i @dimah-s3/react
```

## 1. Create the React client and provider [#1-create-the-react-client-and-provider]

Create the typed React client with `createS3Client`.

<Tabs items={["@dimah-s3/server", "Bring your own backend"]}>

<Tab value="@dimah-s3/server">

```ts title="lib/s3-client.ts"
"use client";

import { createS3Client } from "@dimah-s3/react";

export const s3Client = createS3Client();
export const S3Provider = s3Client.Provider;
```

To configure custom base paths, headers, or credentials:

```ts
export const s3Client = createS3Client({
  basePath: "/api/s3", // [!code ++]
  credentials: "include", // [!code ++]
  headers: async () => ({
    // [!code ++]
    Authorization: `Bearer ${await getAuthToken()}`, // [!code ++]
  }), // [!code ++]
});
```

</Tab>

<Tab value="Bring your own backend">

If you are using a custom backend API instead of `@dimah-s3/server`, implement `S3Api` using `defineApi`:

```tsx title="components/s3-provider.tsx"
"use client";

import { S3Provider } from "@dimah-s3/react";
import { api } from "@/lib/s3-api";

export function AppS3Provider({ children }: { children: React.ReactNode }) {
  return <S3Provider api={api}>{children}</S3Provider>;
}
```

See [Bring Your Own Backend](https://v1.s3.dimah.dev/docs/react/custom-backend) for protocol specifications.

</Tab>

</Tabs>

## 2. Mount S3Provider [#2-mount-s3provider]

Mount `<S3Provider>` near your application root:

<Tabs items={["Next.js (App Router)", "Vite / SPA"]}>

<Tab value="Next.js (App Router)">

```tsx title="app/layout.tsx"
import { S3Provider } from "@/lib/s3-client"; // [!code ++]

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        {/* [!code ++] */}
        <S3Provider>{children}</S3Provider>
      </body>
    </html>
  );
}
```

</Tab>

<Tab value="Vite / SPA">

```tsx title="src/main.tsx"
import React from "react";
import ReactDOM from "react-dom/client";
import { S3Provider } from "./lib/s3-client"; // [!code ++]
import { App } from "./app";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    {/* [!code ++] */}
    <S3Provider>
      <App />
    </S3Provider>
  </React.StrictMode>,
);
```

</Tab>

</Tabs>

## 3. Call your first hook [#3-call-your-first-hook]

Use `useUpload` with a route name matching your server config:

```tsx title="app/file-uploader.tsx"
"use client";

import { useUpload } from "@dimah-s3/react";

export function FileUploader() {
  const upload = useUpload({
    route: "avatar",
  });

  return (
    <div
      {...upload.getRootProps()}
      className="cursor-pointer rounded border p-4 text-center"
    >
      <input {...upload.getInputProps()} />
      {upload.isUploading
        ? `Uploading: ${upload.progress.percent}%`
        : "Click or drop files here"}
    </div>
  );
}
```

---

## TypeScript route inference [#typescript-route-inference]

Enable autocompletion and type checking for route names across hooks and components:

```ts title="lib/s3-routes.ts"
import type { InferS3Routes } from "@dimah-s3/core";
import type { s3 } from "@/lib/s3";

declare module "@dimah-s3/core" {
  // [!code ++]
  interface DimahS3Routes extends Record<InferS3Routes<typeof s3>, true> {} // [!code ++]
}
```

---

## Type reference [#type-reference]

```ts
import type { CreateS3ClientOptions } from "@dimah-s3/react";
```

### CreateS3ClientOptions [#creates3clientoptions]

<AutoTypeTable
  path="packages/core/src/create-s3-client.ts"
  name="CreateS3ClientOptions"
/>

## Frequently asked questions [#frequently-asked-questions]

<Accordions>

<Accordion title="How do I automatically sync file constraints from the server?">

Omit `accept` and `maxFileSize` from `useUpload`. By default, the React client
fetches `fileTypes` and `maxFileSize` from `GET /routes` (`api.catalog()`), so
the server remains the source of truth.

</Accordion>

<Accordion title="How do I pass auth tokens or cookies to the API?">

Pass an async `headers` function or `credentials: "include"` in `createS3Client`:

```ts
export const s3Client = createS3Client({
  credentials: "include", // [!code ++]
  headers: async () => ({
    // [!code ++]
    Authorization: `Bearer ${getStoredToken()}`, // [!code ++]
  }), // [!code ++]
});
```

</Accordion>

</Accordions>
