# Source: https://react-spectrum.adobe.com/getting-started.md

# Getting started

## Installation

Install React Spectrum with your preferred package manager.

```bash
npm install @react-spectrum/s2
```

## Framework setup

<Tabs
  aria-label="Frameworks"
  density="compact"
>
  <TabList><Tab id="parcel"><Parcel/><Text>Parcel</Text></Tab><Tab id="webpack"><Webpack/><Text>webpack</Text></Tab><Tab id="vite"><Vite/><Text>Vite</Text></Tab><Tab id="next"><Nextjs/><Text>Next.js</Text></Tab><Tab id="react-router"><ReactRouter/><Text>React Router</Text></Tab><Tab id="rollup"><Rollup/><Text>Rollup</Text></Tab><Tab id="esbuild"><ESBuild/><Text>ESBuild</Text></Tab></TabList>

  <TabPanel id="parcel">
    To use React Spectrum in a client-only Parcel SPA, setup style macros, configure React Spectrum links to use your client side router, and optimize the client bundle to include localized strings for your supported languages.

    <StepList>
      <Step>
        <Counter/>React Spectrum supports styling via [macros](https://parceljs.org/features/macros/), a new bundler feature that enables functions to run at build time. To optimize CSS generated by style macros into a single [shared bundle](https://parceljs.org/features/code-splitting/#manual-shared-bundles), add the following to your project root `package.json`:

        ```json
        {
          "@parcel/bundler-default": {
            "manualSharedBundles": [
              {
                "name": "s2-styles",
                "types": ["css"],
                "assets": [
                  "**/@react-spectrum/s2/**",
                  // Update this glob as needed to match your source files.
                  "src/**/*.{js,jsx,ts,tsx}"
                ]
              }
            ]
          }
        }
        ```
      </Step>

      <Routers components={props.components}/>

      <Step>
        <Counter/>By default, React Spectrum includes localized strings for 30+ languages. To optimize the JavaScript bundle to include only your supported languages, install our bundler plugin.

        ```bash
        npm install @react-aria/parcel-resolver-optimize-locales
        ```

        Add the following to your `.parcelrc`.

        ```json
        {
          "extends": "@parcel/config-default",
          "resolvers": ["@react-aria/parcel-resolver-optimize-locales", "..."]
        }
        ```

        In your project root `package.json`, add a `"locales"` field containing the languages you want to support.

        ```json
        {
          "locales": ["en-US", "fr-FR"]
        }
        ```
      </Step>
    </StepList>
  </TabPanel>

  <TabPanel id="webpack">
    To use React Spectrum in a client-only webpack SPA, setup style macros, configure React Spectrum links to use your client side router, and optimize the client bundle to include localized strings for your supported languages.

    <StepList>
      <Step>
        <Counter/>React Spectrum supports styling via [macros](https://parceljs.org/features/macros/), a new bundler feature that enables functions to run at build time. To use style macros, install the following plugins:

        ```bash
        npm install unplugin-parcel-macros mini-css-extract-plugin css-minimizer-webpack-plugin swc-minify-webpack-plugin lightningcss browserslist --dev
        ```
      </Step>

      <Step>
        <Counter/>Edit `webpack.config.js`:

        ```ts
        // webpack.config.js
        const macros = require('unplugin-parcel-macros');
        const MiniCssExtractPlugin = require("mini-css-extract-plugin");
        const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
        const {SwcMinifyWebpackPlugin} = require("swc-minify-webpack-plugin");
        const {browserslistToTargets} = require('lightningcss');
        const browserslist = require('browserslist');

        // Adjust this to target the browsers your product supports.
        // https://browserslist.dev/
        const BROWSERSLIST = 'last 2 Chrome versions, last 2 Safari versions, last 2 Firefox versions';

        module.exports = {
          // ...
          plugins: [
            // Enable style macros.
            macros.webpack(),
            // Extract CSS bundles.
            new MiniCssExtractPlugin({
              // Use content hash in filename for long term cacheability.
              filename: '[name].[contenthash].css',
              // Ignore warnings about CSS order. Style macros generate atomic CSS,
              // which is resilient to ordering differences.
              ignoreOrder: true
            })
          ],
          optimization: {
            // Always enable minimizer plugins (even in development), to reduce duplicate CSS rules.
            minimize: true,
            minimizer: [
              // Minify JavaScript during the production build only.
              // (Used SWC here, but you can also use Terser if you prefer.)
              argv.mode === 'production'
                ? new SwcMinifyWebpackPlugin()
                : null,
              // Use lightningcss to compile CSS. This removes duplicate rules and outputs compatible CSS for your browserslist.
              // In production it also minifies.
              new CssMinimizerPlugin({
                minify: CssMinimizerPlugin.lightningCssMinify,
                minimizerOptions: {
                  minify: argv.mode === 'production',
                  targets: browserslistToTargets(browserslist(BROWSERSLIST))
                }
              })
            ],
            splitChunks: {
              cacheGroups: {
                // Bundle all S2 and style-macro generated CSS into a single bundle instead of code splitting.
                // Because atomic CSS has so much overlap between components, loading all CSS up front results in
                // smaller bundles instead of producing duplication between pages.
                s2: {
                  name: 's2-styles',
                  test(module) {
                    return module.type === 'css/mini-extract' && (module.identifier().includes('@react-spectrum/s2') || /\.macro-(.*?)\.css/.test(module.identifier()));
                  },
                  chunks: 'all',
                  enforce: true
                }
              }
            }
          }
        };
        ```
      </Step>

      <Routers components={props.components}/>

      <Step>
        <Counter/>By default, React Spectrum includes localized strings for 30+ languages. To optimize the JavaScript bundle to include only your supported languages, install our bundler plugin.

        ```bash
        npm install @react-aria/optimize-locales-plugin
        ```

        Edit `webpack.config.ts` to add the plugin, and configure the `locales` parameter.

        ```ts
        // webpack.config.js
        const optimizeLocales = require('@react-aria/optimize-locales-plugin');

        module.exports = {
          // ...
          plugins: [
            optimizeLocales.webpack({
              locales: ['en-US', 'fr-FR']
            })
          ]
        };
        ```
      </Step>
    </StepList>
  </TabPanel>

  <TabPanel id="vite">
    To use React Spectrum in a client-only Vite SPA, setup style macros, configure React Spectrum links to use your client side router, and optimize the client bundle to include localized strings for your supported languages.

    <StepList>
      <Step>
        <Counter/>React Spectrum supports styling via [macros](https://parceljs.org/features/macros/), a new bundler feature that enables functions to run at build time. To use style macros, install the bundler plugin:

        ```bash
        npm install unplugin-parcel-macros --dev
        ```
      </Step>

      <Step>
        <Counter/>Edit `vite.config.ts` to add the plugin and optimize the CSS bundle:

        ```ts
        // vite.config.ts
        import {defineConfig} from 'vite';
        import react from '@vitejs/plugin-react';
        import macros from 'unplugin-parcel-macros';

        export default defineConfig({
          plugins: [
            macros.vite(), // Must be first!
            react()
          ],
          build: {
            target: ['es2022'],
            // Lightning CSS produces a much smaller CSS bundle than the default minifier.
            cssMinify: 'lightningcss',
            rollupOptions: {
              output: {
                // Bundle all S2 and style-macro generated CSS into a single bundle instead of code splitting.
                // Because atomic CSS has so much overlap between components, loading all CSS up front results in
                // smaller bundles instead of producing duplication between pages.
                manualChunks(id) {
                  if (/macro-(.*)\.css$/.test(id) || /@react-spectrum\/s2\/.*\.css$/.test(id)) {
                    return 's2-styles';
                  }
                }
              }
            }
          }
        });
        ```
      </Step>

      <Routers components={props.components}/>

      <Step>
        <Counter/>By default, React Spectrum includes localized strings for 30+ languages. To optimize the JavaScript bundle to include only your supported languages, install our bundler plugin.

        ```bash
        npm install @react-aria/optimize-locales-plugin
        ```

        Edit `vite.config.ts` to add the plugin, and configure the `locales` parameter.

        ```ts
        // vite.config.ts
        import {defineConfig} from 'vite';
        import optimizeLocales from '@react-aria/optimize-locales-plugin';

        export default defineConfig({
          plugins: [
            // ...
            {
              ...optimizeLocales.vite({
                locales: ['en-US', 'fr-FR']
              }),
              enforce: 'pre'
            }
          ],
        });
        ```
      </Step>
    </StepList>
  </TabPanel>

  <TabPanel id="next">
    To use React Spectrum with Next.js (app router), setup style macros, ensure the locale on the server matches the client, and configure React Spectrum links to use the Next.js router.

    <InlineAlert variant="notice">
      <Heading>Turbopack is not supported</Heading>
      <Content>`unplugin-parcel-macros` currently only works with webpack, not Turbopack. When using Next.js 16 or later, make sure to start your app with the `--webpack` flag.</Content>
    </InlineAlert>

    <StepList>
      <Step>
        <Counter/>React Spectrum supports styling via [macros](https://parceljs.org/features/macros/), a new bundler feature that enables functions to run at build time. To use style macros, install the bundler plugin:

        ```bash
        npm install unplugin-parcel-macros --dev
        ```
      </Step>

      <Step>
        <Counter/>Edit `next.config.ts` to add the plugin and optimize the CSS:

        ```js
        // next.config.ts
        import macros from 'unplugin-parcel-macros';

        // Create a single instance of the plugin that's shared between server and client builds.
        let plugin = macros.webpack();

        export default {
          webpack(config) {
            config.plugins.push(plugin);

            // Bundle all S2 and style-macro generated CSS into a single bundle instead of code splitting.
            // Because atomic CSS has so much overlap between components, loading all CSS up front results in
            // smaller bundles instead of producing duplication between pages.
            config.optimization.splitChunks ||= {};
            config.optimization.splitChunks.cacheGroups ||= {};
            config.optimization.splitChunks.cacheGroups.s2 = {
              name: 's2-styles',
              test(module) {
                return (module.type === 'css/mini-extract' && module.identifier().includes('@react-spectrum/s2')) || /macro-(.*?)\.css/.test(module.identifier());
              },
              chunks: 'all',
              enforce: true
            };

            return config;
          }
        };
        ```
      </Step>

      <Step>
        <Counter/>Create `app/provider.tsx`. This should render a [Provider](Provider.md) to set the locale, page background, and color scheme, load Spectrum fonts, and integrate with the Next.js router. When using S2 together with other versions of Spectrum, ensure that the S2 provider is the inner-most provider.

        ```tsx
        // app/provider.tsx
        "use client";

        import {useRouter} from 'next/navigation';
        import {Provider} from '@react-spectrum/s2';

        // Configure the type of the `routerOptions` prop on all React Spectrum components.
        declare module '@react-spectrum/s2' {
          interface RouterConfig {
            routerOptions: NonNullable<Parameters<ReturnType<typeof useRouter>['push']>[1]>
          }
        }

        export function ClientProvider({lang, children}) {
          let router = useRouter();

          return (
            <Provider elementType="html" locale={lang} router={{navigate: router.push}}>
              {children}
            </Provider>
          );
        }
        ```
      </Step>

      <Step>
        <Counter/>In your root layout, determine the user's preferred language and render a `ClientProvider` in place of the `<html>` element.

        ```tsx
        // app/layout.tsx
        import {headers} from 'next/headers';
        import {ClientProvider} from './provider';

        export default async function RootLayout({children}) {
          // Get the user's preferred language from the Accept-Language header.
          // You could also get this from a database, URL param, etc.
          const acceptLanguage = (await headers()).get('accept-language');
          const lang = acceptLanguage?.split(/[,;]/)[0] || 'en-US';

          return (
            <ClientProvider lang={lang}>
              <body>
                {children}
              </body>
            </ClientProvider>
          );
        }
        ```
      </Step>
    </StepList>
  </TabPanel>

  <TabPanel id="react-router">
    To use React Spectrum with React Router (framework mode), setup style macros, ensure the locale on the server matches the client, and configure React Spectrum links to use client side routing. If you're using declarative mode, choose your bundler above.

    <StepList>
      <Step>
        <Counter/>React Spectrum supports styling via [macros](https://parceljs.org/features/macros/), a new bundler feature that enables functions to run at build time. To use style macros, install the bundler plugin:

        ```bash
        npm install unplugin-parcel-macros --dev
        ```
      </Step>

      <Step>
        <Counter/>Edit `vite.config.ts` to add the plugin and optimize the CSS bundle:

        ```ts
        // vite.config.ts
        import {defineConfig} from 'vite';
        import macros from 'unplugin-parcel-macros';

        export default defineConfig({
          plugins: [
            macros.vite(), // Must be first!
            // ...
          ],
          build: {
            target: ['es2022'],
            // Lightning CSS produces a much smaller CSS bundle than the default minifier.
            cssMinify: 'lightningcss',
            rollupOptions: {
              output: {
                // Bundle all S2 and style-macro generated CSS into a single bundle instead of code splitting.
                // Because atomic CSS has so much overlap between components, loading all CSS up front results in
                // smaller bundles instead of producing duplication between pages.
                manualChunks(id) {
                  if (/macro-(.*)\.css$/.test(id) || /@react-spectrum\/s2\/.*\.css$/.test(id)) {
                    return 's2-styles';
                  }
                }
              }
            }
          }
        });
        ```
      </Step>

      <Step>
        <Counter/>In your root layout, determine the user's preferred language in a `loader` function and render a [Provider](Provider.md) to set the locale, page background, and color scheme, load Spectrum fonts, and integrate with React Router. When using S2 together with other versions of Spectrum, ensure that the S2 provider is the inner-most provider.

        ```tsx
        // app/root.tsx
        import {Provider} from '@react-spectrum/s2';
        import {useNavigate, useHref, useRouteLoaderData, type NavigateOptions, type LoaderFunctionArgs} from 'react-router';
        import type { Route } from "./+types/root";

        /*- begin highlight -*/
        // Configure the type of the `routerOptions` prop on all React Spectrum components.
        declare module '@react-spectrum/s2' {
          interface RouterConfig {
            routerOptions: NavigateOptions
          }
        }
        /*- end highlight -*/

        export async function loader({request}: Route.LoaderArgs) {
          // Get the requested language (e.g. from headers, URL param, database, etc.)
          /*- begin highlight -*/
          const acceptLanguage = request.headers.get('accept-language');
          const lang = acceptLanguage?.split(/[,;]/)[0] || 'en-US';
          /*- end highlight -*/
          return {lang};
        }

        export function Layout({children}) {
          /*- begin highlight -*/
          let {lang} = useRouteLoaderData('root') || {lang: 'en-US'};
          let navigate = useNavigate();
          /*- end highlight -*/

          return (
            /*- begin highlight -*/
            <Provider elementType="html" locale={lang} router={{navigate, useHref}}>
            {/*- end highlight -*/}
              <head>
                {/* ... */}
              </head>
              <body>
                {/*- begin highlight -*/}
                {/*- end highlight -*/}
                {children}
                {/* ... */}
              </body>
            </Provider>
          );
        }
        ```
      </Step>

      <Step>
        <Counter/>By default, React Spectrum includes localized strings for 30+ languages. To optimize the JavaScript bundle to include only your supported languages, install our bundler plugin.

        ```bash
        npm install @react-aria/optimize-locales-plugin
        ```

        Edit `vite.config.ts` to add the plugin, and configure the `locales` parameter.

        ```ts
        // vite.config.ts
        import {defineConfig} from 'vite';
        import optimizeLocales from '@react-aria/optimize-locales-plugin';

        export default defineConfig({
          plugins: [
            {
              ...optimizeLocales.vite({
                locales: ['en-US', 'fr-FR']
              }),
              enforce: 'pre'
            }
          ],
        });
        ```
      </Step>
    </StepList>
  </TabPanel>

  <TabPanel id="rollup">
    To use React Spectrum in a client-only Rollup SPA, setup style macros, configure React Spectrum links to use your client side router, and optimize the client bundle to include localized strings for your supported languages.

    <StepList>
      <Step>
        <Counter/>React Spectrum supports styling via [macros](https://parceljs.org/features/macros/), a new bundler feature that enables functions to run at build time. To use style macros, install the bundler plugin:

        ```bash
        npm install unplugin-parcel-macros --dev
        ```
      </Step>

      <Step>
        <Counter/>Edit `rollup.config.js` to add the plugin and optimize the CSS bundle:

        ```ts
        // rollup.config.ts
        import macros from 'unplugin-parcel-macros';

        export default {
          plugins: [
            macros.rollup(), // Must be first!
            // ...
          ],
          output: {
            // Bundle all S2 and style-macro generated CSS into a single bundle instead of code splitting.
            // Because atomic CSS has so much overlap between components, loading all CSS up front results in
            // smaller bundles instead of producing duplication between pages.
            manualChunks(id) {
              if (/macro-(.*)\.css$/.test(id) || /@react-spectrum\/s2\/.*\.css$/.test(id)) {
                return 's2-styles';
              }
            }
          }
        };
        ```
      </Step>

      <Routers components={props.components}/>

      <Step>
        <Counter/>By default, React Spectrum includes localized strings for 30+ languages. To optimize the JavaScript bundle to include only your supported languages, install our bundler plugin.

        ```bash
        npm install @react-aria/optimize-locales-plugin
        ```

        Edit `rollup.config.js` to add the plugin, and configure the `locales` parameter.

        ```ts
        // rollup.config.js
        import optimizeLocales from '@react-aria/optimize-locales-plugin';

        export default {
          // ...
          plugins: [
            optimizeLocales.rollup({
              locales: ['en-US', 'fr-FR']
            })
          ]
        };
        ```
      </Step>
    </StepList>
  </TabPanel>

  <TabPanel id="esbuild">
    To use React Spectrum in a client-only ESBuild SPA, setup style macros, configure React Spectrum links to use your client side router, and optimize the client bundle to include localized strings for your supported languages.

    <StepList>
      <Step>
        <Counter/>React Spectrum supports styling via [macros](https://parceljs.org/features/macros/), a new bundler feature that enables functions to run at build time. To use style macros, install the bundler plugin:

        ```bash
        npm install unplugin-parcel-macros --dev
        ```
      </Step>

      <Step>
        <Counter/>Edit your build script to add the plugin:

        ```ts
        // build.mjs
        import {build} from 'esbuild';
        import macros from 'unplugin-parcel-macros';

        build({
          plugins: [
            macros.esbuild(), // Must be first!
            // ...
          ]
        });
        ```
      </Step>

      <Routers components={props.components}/>

      <Step>
        <Counter/>By default, React Spectrum includes localized strings for 30+ languages. To optimize the JavaScript bundle to include only your supported languages, install our bundler plugin.

        ```bash
        npm install @react-aria/optimize-locales-plugin
        ```

        Edit your build script to add the plugin, and configure the `locales` parameter.

        ```ts
        import {build} from 'esbuild';
        import optimizeLocales from '@react-aria/optimize-locales-plugin';

        build({
          // ...
          plugins: [
            optimizeLocales.esbuild({
              locales: ['en-US', 'fr-FR']
            })
          ]
        });
        ```
      </Step>
    </StepList>
  </TabPanel>
</Tabs>