Introducing Amplify UI's React Components
Published: 2022-07-07 14:35:47

> **June 27, 2024:** This blog post uses Amplify Gen 1, if you're starting a new Amplify app I recommend trying out [Gen 2](https://dev.to/aws/introducing-a-new-fullstack-typescript-dx-for-aws-1ap9)!

This week, my team at AWS launched React UI components which are really fun to build with - I want to show you all some of what you can create!

AWS Amplify UI is a set of primitive and cloud-connected components that enable customization, themability, and accessibility. There are primitive components for creating layouts, buttons, headers, ratings, and more. There are also components that connect to AWS resources to display maps and build authentication flows. Let's build a mapping application to work with the UI library!

![Completed app with header, cards, and map](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i8mhjtfp1u2s97ja5v99.png)

## Start an App

First, create an application - I used Next.js but you could just as easily use Create React App.

```sh
npx create-next-app amplify-ui-demo
cd amplify-ui-demo
```

Then, install the Amplify libraries and UI components:

```sh
npm i aws-amplify @aws-amplify/ui-react
```

Amplify UI doesn't come with a font by default, so you can choose one you like. The default theme uses the Inter font - we'll install that in our app as well.

```sh
npm install @fontsource/inter
```

At the top level of your application in `/pages/_app.js`, import the Amplify CSS file and inter font:

```js
import "@aws-amplify/ui-react/styles.css";
import "@fontsource/inter/variable.css";
```

## Build a Basic UI

Now, let's build out our app's basic UI! We'll do this in our app's home page - `/pages/index.js`. I'll first create an array of restaurants above my React component. Each one will have a name, cuisine, rating, price, and a (randomly generated) latitude and longitude:

```js
const restaurants = [
  {
    name: "Mannys's Burgers",
    cuisine: "American",
    rating: 5,
    price: "$$",
    location: {
      lat: "32.385348495775",
      long: "-85.738272191934",
    },
  },
  {
    name: "Mac n Cheesy",
    cuisine: "American",
    rating: 4,
    price: "$",
    location: {
      lat: "40.385358710927",
      long: "-78.637760520167",
    },
  },
  {
    name: "Giuliano's Italian Restaurant",
    cuisine: "Italian",
    rating: 5,
    price: "$$$",
    location: {
      lat: "35.396328108119",
      long: "-87.786869702867",
    },
  },
  {
    name: "The Pink Sheep",
    cuisine: "Fine Dining",
    rating: null,
    price: "$$$$",
    rating: 3,
    location: {
      lat: "45.386348035105",
      long: "-97.535870048241",
    },
  },
];
```

I'll also pre-emptively import all the UI components I'll need. I'll also import the Next.js Link component.

```js
import {
  withAuthenticator,
  Card,
  Badge,
  Heading,
  Rating,
  Text,
  Link,
  Flex,
  View,
  SearchField,
  useTheme,
  MapView,
} from "@aws-amplify/ui-react";

import NextLink from "next/link";
```

We'll start off by a `View` component which will will render as a `div` by default. We'll keep the Next.js `Head` with a title tag in it.

```js
function Home() {
  return (
    <View>
      <Head>
        <title>RestaurantList</title>
      </Head>
    </View>
  );
}
```

Below the `Head`, let's build a header. We'll first use the `View` component again, but this time we'll render it as a `header` element instead of as a `div`. We'll also add some padding. Then we'll use the `Flex` component for flexbox. You can use props that mirror the flexbox CSS properties! We'll center the content within the row and add space around the items. We'll create another `Flex` and add some `Link`s. We'll also add a heading with a level of `1` with the name of the site. Finally, we'll add another `Flex` with a `SearchField` inside of it.

```js
<View as="header" padding="10px">
  <Flex direction="row" justifyContent="space-around" alignItems="center">
    <Flex>
      <NextLink href="">
        <Link>Home</Link>
      </NextLink>
      <NextLink href="/about">
        <Link>About</Link>
      </NextLink>
      <NextLink href="/shop">
        <Link>Shop</Link>
      </NextLink>{" "}
    </Flex>
    <Heading level={1} textAlign="center">
      RestaurantList
    </Heading>
    <Flex>
      <SearchField />
    </Flex>
  </Flex>
</View>
```

After that, let's loop through our restaurants and add `Card`s for each. We'll create a `Flex` here so that we can display a map next to the cards in the future. Then we'll add a `View` component with a `maxWidth` set. We'll loop through the restaurants and create a `Card` for each. Each `Card` will have information about the Restaurant on the left side, and then a rating on the right. The `Rating` component will render the star rating for each restaurant!

```js
<Flex>
  <View maxWidth="800px">
    {restaurants.map((restaurant) => (
      <Card variation="elevated" key={restaurant.name} margin="10px">
        <Flex direction="row" justifyContent="space-between">
          <Flex direction="column">
            <Heading level={3}>{restaurant.name}</Heading>
            <Badge size="large" variation="info" width="fit-content">
              {restaurant.cuisine}
            </Badge>
            <Text color="grey">{restaurant.price}</Text>
          </Flex>
          <Flex direction="column">
            <Rating value={restaurant.rating} maxValue={5} />
          </Flex>
        </Flex>
      </Card>
    ))}
  </View>
</Flex>
```

Now your UI should look like this:

![UI with header and cards on left side](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/361de9njpox94tau3uj8.png)

## Theming

Amplify UI is fully themeable -- you can make it so the components fully match your brand or style. There are some [example themes](https://github.com/aws-amplify/amplify-ui/tree/326e258d058db247a14f190e37083b635170035d/docs/src/components/home/themes) used within the Amplify UI docs that totally change how the UI looks!

In this case, I'll change up some of the colors used. I'll use green as the primary theme color and yellow as the secondary. I'll add the theme object to the `_app.js` file. Amplify UI has colors builtin which is where the green and yellow are coming from, but you could also set these values to completely custom colors.

```js
const earthyTheme = {
  name: "earthTheme",
  tokens: {
    colors: {
      brand: {
        primary: {
          10: { value: "{colors.green.10}" },
          20: { value: "{colors.green.20}" },
          40: { value: "{colors.green.40}" },
          60: { value: "{colors.green.60}" },
          80: { value: "{colors.green.80}" },
          90: { value: "{colors.green.90}" },
          100: { value: "{colors.green.100}" },
        },
        secondary: {
          10: { value: "{colors.yellow.10}" },
          20: { value: "{colors.yellow.20}" },
          40: { value: "{colors.yellow.40}" },
          60: { value: "{colors.yellow.60}" },
          80: { value: "{colors.yellow.80}" },
          90: { value: "{colors.yellow.90}" },
          100: { value: "{colors.yellow.100}" },
        },
      },
    },
  },
};
```

To use the theme, import the `ThemeProvider` component.

```js
import { ThemeProvider } from "@aws-amplify/ui-react";
```

Then, wrap the top-level application component in the `ThemeProvider` and pass the `theme` prop set to the theme object.

```js
function MyApp({ Component, pageProps }) {
  return (
    <ThemeProvider theme={earthyTheme}>
      <Component {...pageProps} />
    </ThemeProvider>
  );
}
```

### Using Themes in Components

You can also use attributes from themes directly within your components in order to style them. Inside the `Home` component in `index.js`, use the `useTheme` hook.

```js
const { tokens } = useTheme();
```

Then, let's set the background color of the header to the primary color from the theme:

```js
<View as="header" padding="10px" backgroundColor={tokens.colors.brand.primary[40]}>
```

If the primary brand color changes in the future, the header will update to match!

## Cloud Connected Components

Amplify UI also offers cloud connected components so that you can connect to AWS services directly from React components. First, install the Amplify CLI. If it's your first time using Amplify, you'll need to [configure](https://docs.amplify.aws/cli/start/install/#install-the-amplify-cli) it as well.

```sh
npm install -g @aws-amplify/cli
```

Then, initialize Amplify within your project:

```js
amplify init
```

When prompted, choose a name for your project and then respond "Yes" to initialize with the defaults. Choose your AWS Profile as well.

Now, add authentication to your project by running:

```sh
amplify add auth
```

Press enter for the default configuration, then choose Username and "No, I am done".

Then add mapping to your app:

```sh
amplify add geo
```

Answer the questions as follows (though choose any name for the map):

```sh
? Select which capability you want to add: Map (visualize the geospatial data)
✔ Provide a name for the Map: · map53122572
✔ Who can access this Map? · Authorized and Guest users
Available advanced settings:
- Map style & Map data provider (default: Streets provided by Esri)

✔ Do you want to configure advanced settings? (y/N) · no
```

Run `amplify push` to deploy your resources.

You'll then need to configure Amplify within your application code. Inside the `./pages/_app.js` file add the following:

```js
import awsExports from "../src/aws-exports";
import { Amplify } from "aws-amplify";

Amplify.configure(awsExports);
```

Let's first add a map component to the app. Inside the `Flex` and under the close of the `</View>` for the restaurant cards, let's add a `MapView`. The latitude and longitude are for the United States, you may want to play around with the zoom level.

```js
<MapView
  initialViewState={{
    latitude: "37.0902",
    longitude: "-95.7129",
    zoom: 4,
  }}
></MapView>
```

Let's also add markers for each of our restaurants. We'll use `react-map-gl` for these.

Install the package:

```
npm i react-map-gl
```

Import the markers:

```js
import { Marker } from "react-map-gl";
```

Then, inside the MapView tags, render the `Marker`s.

```js
{
  restaurants.map((restaurant) => (
    <Marker
      key={restaurant.name}
      latitude={restaurant.location.lat}
      longitude={restaurant.location.long}
    />
  ));
}
```

Now you'll have a map!


![Map of US with markers for restaurants](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fr2oq4zxo18ctp8nktzv.png)

Now let's add an authentication flow so users need to sign in to view the map. Wrap the Home component in the higher-order `withAuthenticator` component. Now you'll be prompted to create a user and sign in!

```js
export default withAuthenticator(Home);
```

![Authentication flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jww6q0wae9id3sctqwul.png)

You could also use database data instead of a JavaScript object by using [Amplify's data categories](https://docs.amplify.aws/lib/datastore/getting-started/q/platform/js/).

## Studio

You can also use Amplify Studio to go from Figma designs to cloud-connected code. Under the hood, the generated components will all use Amplify UI. Check out [this tutorial](https://dev.to/aspittel/build-a-map-application-on-aws-in-10-steps-3ofa) to learn how to build a similar application using that workflow.

## Conclusion

In this tutorial, we built a UI with both primitive and cloud-connected Amplify UI components. If you'd like to disconnect your app from the cloud and delete the authentication and geo resources, run `amplify delete`. As you build with Amplify UI, we'd love to [hear your feedback](https://github.com/aws-amplify/amplify-ui)!