Amplify UI

Overview

A Theme is a structured collection of design decisions that change the appearance of a UI library. An Amplify UI theme is a structured object of design tokens, breakpoints, and overrides. The goals of the Amplify UI theme are:

  1. Leverage platform technologies as much as possible for performance and broad support. This means plain CSS and CSS variables. You can always fall back to writing CSS (or a pre-processer to CSS like Sass).
  2. Use framework-specific patterns to provide an easier developer experience. This means providing an extendable theme which generates CSS and CSS variables for your application.

Getting started

Step 1: Wrap your App with ThemeProvider

import { ThemeProvider } from '@aws-amplify/ui-react';
const App = (
  <ThemeProvider>
    <MyApp>/* AmplifyUI */</MyApp>
  </ThemeProvider>
);

Step 2: Use the theme to style components

// Option 1: Use the theme through component variations
import { Text } from '@aws-amplify/ui-react';
const MyComponent = ({ children }) => {
  return <Text variation="primary">{children}</Text>;
};

// Option 2: Get the theme object through the useTheme hook and style components with it
import { Text, useTheme } from '@aws-amplify/ui-react';
const MyComponent = ({ children }) => {
  const { tokens } = useTheme();
  return <Text color={tokens.colors.font.tertiary}>{children}</Text>;
};

Optional: To extend or override a token in the default theme, create a custom theme:

import { ThemeProvider, Theme } from '@aws-amplify/ui-react';

// Step 1: Create a new Theme with your custom values
const theme = {
  name: 'my-theme',
  tokens: {
    colors: {
      font: {
        primary: { value: '#008080' },
        // ...
      },
    },
  },
};

// Step 2: Pass the new theme to `ThemeProvider`
// this will apply the theme to all Amplify UI components
const App = (
  <ThemeProvider theme={theme}>
    <MyApp>/* AmplifyUI */</MyApp>
  </ThemeProvider>
);
import { ThemeProvider, Theme } from '@aws-amplify/ui-react';

// Step 1: Create a new Theme with your custom values
const theme: Theme = {
  name: 'my-theme',
  tokens: {
    colors: {
      font: {
        primary: { value: '#008080' },
        // ...
      },
    },
  },
};

// Step 2: Pass the new theme to `ThemeProvider`
// this will apply the theme to all Amplify UI components
const App = (
  <ThemeProvider theme={theme}>
    <MyApp>/* AmplifyUI */</MyApp>
  </ThemeProvider>
);

Theme object

The theme object is where you define tokens for color palette, font stacks, spacing, and more. By default it will extend from the defaultTheme Amplify UI provides.

export const myTheme = {
  name: 'my-theme',
  tokens: {
    colors: {
      font: {
        primary: { value: 'red' },
      },
    },
  },
};

CSS

You can theme Amplify UI using CSS and CSS variables if you do not want to use the theme object structure. Amplify UI components use plain CSS so styling components can be done with CSS (or a pre-processor like Sass). All of the design tokens defined in the Amplify theme are CSS variables which can be overridden:

:root, [data-amplify-theme] {
  --amplify-colors-font-primary: #333;
  /* you can also use references: */
  --amplify-colors-font-secondary: var(--amplify-colors-neutral-60);
}

If you want more customization than the design tokens provide, you can also override the CSS for components:

/* All components have a class name starting with `amplify` */
.amplify-button {
  font-size: 2rem;
  padding: 1rem 2rem;
  background: none;
  border: 2px solid black;
}

.amplify-button:hover {
  background: gray;
}

Or if you prefer you can use alternative styling with a styling libraries

Unstyled

Amplify UI components can be use unstyled if you want full control over the look-and-feel. To use the components unstyled, import them as you normally would and do not import the CSS.

import { Button, Card } from '@aws-amplify/ui-react';

// don't import the CSS:
// import '@aws-amplify/ui-react/styles.css';

export const App = () => {
  // ...
};

Theme Structure

Design Tokens

Amplify UI uses Design Tokens for storing design decisions and is the primary way to theme the components. Design tokens are categorized by type under namespaces; for example, colors go under the colors namespace. Stitches, Chakra-UI, and Evergreen use a similar convention for organizing their design tokens.

*/
interface BaseTokens<Output extends OutputVariantKey = unknown> {
  borderWidths?: BorderWidths<Output>;
  colors?: Colors<Output>;
  fonts?: Fonts<Output>;
  fontSizes?: FontSizes<Output>;
  fontWeights?: FontWeights<Output>;
  lineHeights?: LineHeights<Output>;
  opacities?: Opacities<Output>;
  outlineOffsets?: OutlineOffsets<Output>;
  outlineWidths?: OutlineWidths<Output>;
  radii?: Radii<Output>;
  shadows?: Shadows<Output>;
  space?: Space<Output>;
  time?: Time<Output>;
  transforms?: Transforms<Output>;
}

References

One import thing about design tokens is they can reference other design tokens. The default theme tokens use references a lot to make a robust system where you can modify a few tokens to have a large effect. The syntax for design token references follows the draft W3C Design Tokens Community Group specification

const myTheme = {
  name: 'my-theme',
  tokens: {
    colors: {
      font: {
        // references colors.neutral.100
        // because the default theme defines that color already
        // we don't need to re-define it here
        primary: { value: '{colors.neutral.100.value}' },
      },
    },
  },
};

Component token definitions

Amplify UI follows a consistent pattern when defining tokens for a component's states and variations. This is helpful for discovering what tokens are available for theming different aspects of a component. Amplify UI uses the following pattern:

component[modifier][_state][child];

A modifier could be a distinct style variation, like the primary or link variant for the Button component. A modifier could also be a variation based on size, such as small, medium, or large.

State typically refers to a change in the component due to an interaction from the user or application itself, such as hover, focus, loading or disabled. Note: Amplify UI prefixes states with an underscore, _, to help distinguish state names from modifier names.

The Button component is a good example of a token definition that includes multiple states and modifiers and follows this pattern:

export const button = {
  //  ... default tokens

  // states
  _hover: {},
  _focus: {},
  _loading: {},
  _disabled: {},

  // variations with states
  primary: {
    _hover: {},
    _focus: {},
    _loading: {},
    _disabled: {},
  },

  // size modifiers
  small: {},
  large: {},
};

Compiled, this would create the following CSS custom properties:

--amplify-component-button-hover-token: value,
--amplify-component-button-focus-token: value,
--amplify-component-button-hover-loading: value,
--amplify-component-button-focus-disabled: value,
--amplify-component-button-primary-hover-token: value,
--amplify-component-button-primary-focus-token: value,
--amplify-component-button-primary-hover-loading: value,
--amplify-component-button-primary-focus-disabled: value,
--amplify-component-button-small-token: value,
--amplify-component-button-large-token: value,

Fonts

Amplify UI allows custom fonts to be used in the theme. The font tokens are defined in the fonts namespace. You can define your primary font stack and fallback font stack values the same way you would do in a CSS font-family rule.

const myTheme = {
  name: 'my-theme',
  tokens: {
    fonts: {
      default: {
        variable: { value: 'Raleway, sans-serif' },
        static: { value: 'Raleway, sans-serif' },
      },
    },
  },
};

Breakpoints

Breakpoints allow you to set media query breakpoints for responsive design. You can then define breakpoint-specific token overrides or use the breakpoints for different layouts in Javascript.

type BreakpointKey = 'base' | 'small' | 'medium' | 'large' | 'xl' | 'xxl';

export interface Breakpoints {
  values: Record<BreakpointKey, number>;
  defaultBreakpoint: BreakpointKey;
}

// Breakpoint unit is in pixels
export const breakpoints: Breakpoints = {
  values: {
    base: 0,
    small: 480, // breakpoint unit is px
    medium: 768,
    large: 992,
    xl: 1280,
    xxl: 1536,
  },
  defaultBreakpoint: 'base',
};

You can modify default breakpoints in your theme's breakpoints definition:

const myTheme = {
  name: 'my-theme',
  breakpoints: {
    // Will be deep merged with the default theme
    // so you don't have to override all the breakpoint values
    values: {
      // default unit is 'em'
      medium: 50,
    },
  },
  //...
};

Note: Unfortunately right now CSS media queries do not support CSS variables so there is no way to customize the breakpoints using only CSS.

Overrides

An override is a collection of design tokens that should take precedence in certain situations, like dark mode. Overrides are built into the theme configuration, but kept separate, so that Amplify UI can use CSS for overriding parts of the theme.

import { defaultTheme } from '@aws-amplify/ui-react';

export const theme = {
  name: 'my-theme',
  overrides: [
    {
      colorMode: 'dark',
      tokens: {
        colors: {
          neutral: {
            10: { value: defaultTheme.tokens.colors.neutral[100].value },
            20: { value: defaultTheme.tokens.colors.neutral[90].value },
            40: { value: defaultTheme.tokens.colors.neutral[80].value },
            80: { value: defaultTheme.tokens.colors.neutral[40].value },
            90: { value: defaultTheme.tokens.colors.neutral[20].value },
            100: { value: defaultTheme.tokens.colors.neutral[10].value },
          },
          black: { value: '#fff' },
          white: { value: '#000' },
        },
      },
    },
    {
      breakpoint: 'large',
      tokens: {
        space: {
          small: { value: '1rem' },
          medium: { value: '2rem' },
          large: { value: '3rem' },
        },
      },
    },
  ],
};

You can override design tokens in CSS by using a media query or adding extra selectors to [data-amplify-theme="{theme.name}"].

@media (prefers-color-scheme: dark) {
  [data-amplify-theme='my-theme'] {
    --amplify-colors-black: #fff;
    --amplify-colors-white: #fff;
  }
}

[data-amplify-theme='my-theme'].disco {
  --amplify-colors-font-primary: pink;
}

Merging multiple themes

If you have multiple themes, you can extend your base theme using the createTheme function.

import { createTheme, defaultTheme } from '@aws-amplify/ui';

// by default, createTheme extends the defaultTheme.
export const baseBrandTheme = createTheme({
  name: 'base-brand-theme',
  tokens: {
    colors: {
      font: {
        primary: { value: 'red' },
      },
    },
  },
});

export const otherBrandTheme = createTheme(
  {
    name: 'other-brand-theme',
    tokens: {
      colors: {
        font: {
          primary: { value: 'blue' },
        },
      },
    },
  },
  baseBrandTheme
);
// The 2nd argument is the base theme to be extended
// if it is omitted, it will use the defaultTheme

Amplify open source software, documentation and community are supported by Amazon Web Services.

© 2024 Amazon Web Services, Inc. and its affiliates. All rights reserved. View the site terms and privacy policy.

Flutter and the related logo are trademarks of Google LLC. We are not endorsed by or affiliated with Google LLC.