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



## Install [#install]

<CodeBlockTabs defaultValue="npm">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="npm">
      npm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="pnpm">
      pnpm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="yarn">
      yarn
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="bun">
      bun
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="npm">
    ```bash
    npm i @dimah-s3/react
    ```
  </CodeBlockTab>

  <CodeBlockTab value="pnpm">
    ```bash
    pnpm add @dimah-s3/react
    ```
  </CodeBlockTab>

  <CodeBlockTab value="yarn">
    ```bash
    yarn add @dimah-s3/react
    ```
  </CodeBlockTab>

  <CodeBlockTab value="bun">
    ```bash
    bun add @dimah-s3/react
    ```
  </CodeBlockTab>
</CodeBlockTabs>

<div className="fd-steps">
  <div className="fd-step">
    ## Create client & provider [#1-create-client--provider]

    Create the typed client instance using `createS3Client`.

    <Tabs items="[&#x22;@dimah-s3/server&#x22;, &#x22;Custom backend&#x22;]">
      <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",
          credentials: "include",
          headers: async () => ({
            Authorization: `Bearer ${await getAuthToken()}`,
          }),
        });
        ```
      </Tab>

      <Tab value="Custom 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 [Custom Backend](https://s3.dimah.dev/docs/react/custom-backend) for protocol specifications.
      </Tab>
    </Tabs>
  </div>

  <div className="fd-step">
    ## Mount S3Provider [#2-mount-s3provider]

    Mount `<S3Provider>` near your application root:

    <Tabs items="[&#x22;Next.js (App Router)&#x22;, &#x22;Vite / SPA&#x22;]">
      <Tab value="Next.js (App Router)">
        ```tsx title="app/layout.tsx"
        import { S3Provider } from "@/lib/s3-client";

        export default function RootLayout({
          children,
        }: {
          children: React.ReactNode;
        }) {
          return (
            <html lang="en">
              <body>
                <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";
        import { App } from "./app";

        ReactDOM.createRoot(document.getElementById("root")!).render(
          <React.StrictMode>
            <S3Provider>
              <App />
            </S3Provider>
          </React.StrictMode>,
        );
        ```
      </Tab>
    </Tabs>
  </div>

  <div className="fd-step">
    ## Call your first hook [#3-call-your-first-hook]

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

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

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

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

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

    ***
  </div>
</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" {
  interface DimahS3Routes extends Record<InferS3Routes<typeof s3>, true> {}
}
```

***

## Type reference [#type-reference]

```ts
import type {
  CreateS3ClientOptions,
  CreateS3ClientResult,
  ReactS3Client,
} 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?">
    By default, hooks fetch constraints (`fileTypes`, `maxFileSize`) automatically from `GET /routes` (`api.catalog()`). You can omit `accept` and `maxFileSize` on `useUpload` so the server remains the single 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",
      headers: async () => ({
        Authorization: `Bearer ${getStoredToken()}`,
      }),
    });
    ```
  </Accordion>
</Accordions>
