> ## Documentation Index
> Fetch the complete documentation index at: https://primer.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# UI styling

> Apply colors, typography, spacing and dark mode with CSS variables on Web, `PrimerTheme` on Android and `PrimerCheckoutTheme` on iOS.

Primer Checkout is fully customizable. You can customize colors, typography, spacing, borders, and component layout (down to the smallest visual detail) without touching internal component code or breaking upgrades.

## Styling methods

> [tab] Web
>
> On the web, Primer Checkout uses **CSS variables** for theming. You can apply styling in two ways - directly in your CSS or through component attributes.
>
> > [tab] CSS
> >
> > ```css styles.css theme={"dark"}
> > primer-checkout {
> >   --primer-color-brand: #2f98ff;
> >   --primer-color-focus: #2f98ff;
> >   --primer-radius-medium: 8px;
> >   --primer-typography-brand: 'Inter', sans-serif;
> > }
> > ```
>
> > [tab] HTML
> >
> > ```html index.html theme={"dark"}
> > <primer-checkout
> >   customStyles='{"primerColorBrand":"#2f98ff","primerColorFocus":"#2f98ff","primerRadiusMedium":"8px"}'
> > ></primer-checkout>
> > ```
> >
> > When passing through a component attribute, convert kebab-case CSS variables to camelCase properties:
> >
> > 1. Remove the leading dashes (`--`)
> > 2. Convert hyphens to camelCase by removing the hyphen and capitalizing the next letter
> >
> > **Examples:**
> >
> > * `--primer-color-brand` → `primerColorBrand`
> > * `--primer-space-medium` → `primerSpaceMedium`
> > * `--primer-typography-body-large-font` → `primerTypographyBodyLargeFont`

> [tab] Android
>
> On Android, Primer Checkout uses a token-based design system through `PrimerTheme`. Pass a custom `PrimerTheme` to your checkout component:
>
> ```kotlin theme={"dark"}
> val theme = PrimerTheme(
>     lightColorTokens = object : LightColorTokens() {
>         override val primerColorBrand: Color = Color(0xFF6C5CE7)
>     },
> )
>
> PrimerCheckoutSheet(
>     checkout = checkout,
>     theme = theme,
> )
> ```

> [tab] iOS
>
> On iOS, Primer Checkout uses `PrimerCheckoutTheme` for theming. Pass a custom theme to your checkout view:
>
> ```swift theme={"dark"}
> let theme = PrimerCheckoutTheme(
>   colors: ColorOverrides(
>     primerColorBrand: .purple
>   ),
>   radius: RadiusOverrides(
>     primerRadiusMedium: 12
>   )
> )
>
> PrimerCheckout(
>   clientToken: clientToken,
>   primerTheme: theme
> )
> ```

## Using styling variables in practice

> [tab] Web
>
> > [tab] With CSS Variables
> >
> > ```css theme={"dark"}
> > primer-checkout {
> >   --primer-color-brand: #663399;
> >   --primer-color-focus: #663399;
> >   --primer-color-loader: #663399;
> >   --primer-color-text-primary: #333333;
> >   --primer-color-text-secondary: rgba(51, 51, 51, 0.62);
> >   --primer-typography-brand: 'Helvetica Neue', sans-serif;
> >   --primer-space-medium: 16px;
> >   --primer-radius-medium: 8px;
> > }
> > ```
>
> > [tab] With customStyles property
> >
> > ```javascript theme={"dark"}
> > const myCustomStyles = {
> >   primerColorBrand: '#663399',
> >   primerColorFocus: '#663399',
> >   primerColorLoader: '#663399',
> >   primerColorTextPrimary: '#333333',
> >   primerTypographyBrand: 'Helvetica Neue, sans-serif',
> >   primerSpaceMedium: '16px',
> >   primerRadiusMedium: '8px',
> > };
> >
> > const checkoutElement = document.querySelector('primer-checkout');
> > checkoutElement.setAttribute('customStyles', JSON.stringify(myCustomStyles));
> > ```
> >
> > This approach is particularly useful when working with JavaScript frameworks or when you need to apply styling variables programmatically.
> >
> > The component will parse the JSON and automatically apply the styles as CSS Variables internally.
>
> You can see all the available styling variables on [the dedicated reference page](https://primer.io/docs/sdk/primer-checkout-web/styling-variables.md).

> [tab] Android
>
> `PrimerTheme` contains five token groups:
>
> | Token Group | Class | What It Controls |
> | - | - | - |
> | Light colors | `LightColorTokens` | All colors in light mode |
> | Dark colors | `DarkColorTokens` | All colors in dark mode |
> | Spacing | `SpacingTokens` | Padding and margins |
> | Typography | `TypographyTokens` | Font sizes, weights, line heights |
> | Radius | `RadiusTokens` | Corner radius for cards, inputs, sheets |
> | Border widths | `WidthTokens` | Border widths for inputs, focus rings |
> | Sizes | `SizeTokens` | Icon sizes and touch targets |
>
> ```kotlin theme={"dark"}
> val brandTheme = PrimerTheme(
>     lightColorTokens = object : LightColorTokens() {
>         override val primerColorBrand: Color = Color(0xFF6C5CE7)
>         override val primerColorBackgroundSecondary: Color = Color(0xFFF7F7F8)
>     },
>     darkColorTokens = object : DarkColorTokens() {
>         override val primerColorBrand: Color = Color(0xFFA29BFE)
>     },
>     spacingTokens = SpacingTokens(
>         small = 6.dp,
>         medium = 10.dp,
>         large = 14.dp,
>     ),
>     radiusTokens = RadiusTokens(
>         medium = 12.dp,
>         large = 20.dp,
>     ),
> )
>
> PrimerCheckoutSheet(
>     checkout = checkout,
>     theme = brandTheme,
> )
> ```
>
> See the [Design Tokens Reference](https://primer.io/docs/checkout/primer-checkout/build-your-ui/design-tokens-explorer-web.md) for a complete list of all available tokens.

> [tab] iOS
>
> `PrimerCheckoutTheme` is organized into seven override categories:
>
> | Category | Parameter | Type | Controls |
> | - | - | - | - |
> | **Colors** | `colors` | `ColorOverrides` | Brand, text, backgrounds, borders, icons in light mode |
> | **Dark colors** | `darkColors` | `ColorOverrides` | The same color tokens in dark mode |
> | **Radius** | `radius` | `RadiusOverrides` | Corner radius for inputs, buttons, cards |
> | **Spacing** | `spacing` | `SpacingOverrides` | Padding and margins |
> | **Sizes** | `sizes` | `SizeOverrides` | Icon sizes and tap targets |
> | **Typography** | `typography` | `TypographyOverrides` | Font family, size, weight, line height, letter spacing |
> | **Border width** | `width` | `WidthOverrides` | Border widths for the default, focus, error and selected states |
>
> ```swift theme={"dark"}
> let theme = PrimerCheckoutTheme(
>   colors: ColorOverrides(
>     primerColorBrand: .indigo,
>     primerColorBackgroundPrimary: Color(.systemBackground),
>     primerColorTextPrimary: Color(.label),
>     primerColorBorderOutlinedFocus: .indigo
>   ),
>   darkColors: ColorOverrides(
>     primerColorBrand: .indigo,
>     primerColorBorderOutlinedFocus: .indigo
>   ),
>   radius: RadiusOverrides(
>     primerRadiusMedium: 10,
>     primerRadiusLarge: 16
>   ),
>   spacing: SpacingOverrides(
>     primerSpaceMedium: 12,
>     primerSpaceLarge: 16
>   ),
>   typography: TypographyOverrides(
>     bodyMedium: .init(font: "Inter", size: 14)
>   ),
>   width: WidthOverrides(
>     primerWidthFocus: 3
>   )
> )
>
> PrimerCheckout(
>   clientToken: clientToken,
>   primerTheme: theme
> )
> ```
>
> Set `brand` in `TypographyOverrides` to one font family name that your app can load, such as a system font or a font you bundle. The default is Inter. Font weights use `Font.Weight` steps, such as `.regular`, `.medium`, `.semibold` and `.bold`.
>
> See the [Design Tokens Explorer](https://primer.io/docs/checkout/primer-checkout/build-your-ui/design-tokens-explorer-ios.md) to preview how tokens affect the checkout, and the [Theming reference](https://primer.io/docs/sdk/ios-checkout/v3.0.0-beta/api/theming/primer-theme.md) for the complete list of `PrimerCheckoutTheme` tokens.

## Theme support

Primer Checkout supports both light and dark themes.

> [tab] Web
>
> The default option is light. To use a dark theme, pass a `primer-dark-theme` CSS class:
>
> ```html theme={"dark"}
> <primer-checkout client-token="your-client-token" class="primer-dark-theme">
> </primer-checkout>
> ```
>
> You can toggle between themes using JavaScript:
>
> ```javascript theme={"dark"}
> function toggleTheme(isDark) {
>   const container = document.querySelector('primer-checkout');
>   container.className = isDark ? 'primer-dark-theme' : 'primer-light-theme';
> }
>
> toggleTheme(true);
> toggleTheme(false);
> ```

> [tab] Android
>
> `DarkColorTokens` extends `LightColorTokens` and overrides base color values. Semantic tokens automatically resolve to the correct values through inheritance:
>
> ```
> Light mode:  primerColorBackgroundPrimary → #FFFFFF
> Dark mode:   primerColorBackgroundPrimary → #171619
> ```
>
> By default the checkout follows the system theme. Set `appearanceMode` to `PrimerAppearanceMode.LIGHT` or `PrimerAppearanceMode.DARK` to pin it to one appearance.
>
> ```kotlin theme={"dark"}
> val theme = PrimerTheme(
>     lightColorTokens = object : LightColorTokens() {
>         override val primerColorBrand: Color = Color(0xFFE53E3E)
>         override val primerColorBackgroundPrimary: Color = Color(0xFFF8F8F8)
>     },
>     darkColorTokens = object : DarkColorTokens() {
>         override val primerColorBrand: Color = Color(0xFFFF6B6B)
>     },
>     appearanceMode = PrimerAppearanceMode.SYSTEM,
> )
> ```
>
> `PrimerTheme` automatically maps color tokens to a Material 3 `ColorScheme`. Material components used within the checkout (like `ModalBottomSheet`) inherit your Primer color tokens without additional configuration.

> [tab] iOS
>
> The checkout follows the system appearance, or the mode you force with `PrimerUIOptions(appearanceMode: .light)` or `.dark`. `colors` applies in light mode only and `darkColors` in dark mode only. Any color you leave out of `darkColors` uses Primer's dark default, not the value from `colors`. To keep a color in dark mode, set it in `darkColors` as well:
>
> ```swift theme={"dark"}
> let theme = PrimerCheckoutTheme(
>   colors: ColorOverrides(
>     primerColorBrand: Color("BrandColor"),                 // Asset catalog color, light appearance
>     primerColorBackgroundPrimary: Color(.systemBackground) // Resolves to its light value
>   ),
>   darkColors: ColorOverrides(
>     primerColorBrand: Color("BrandColor"),                 // Same asset, dark appearance
>     primerColorBackgroundPrimary: Color(.systemBackground) // Resolves to its dark value
>   )
> )
> ```
>
> > [!TIP]
> >
> > Each color resolves for the appearance being drawn. An adaptive color, such as an asset catalog color, `Color(.label)` or `Color(.systemBackground)`, gives its light value in `colors`. In `darkColors` it gives its dark value. Pass the same adaptive color in both to get both variants. `radius`, `spacing`, `sizes`, `typography` and `width` are the same in light and dark mode.

## Try it out

Select a preset or adjust individual tokens to see how styling variables affect the checkout appearance.

> [!NOTE]
>
> This preview shows a subset of styling variables. Interactive states (hover, focus) are not displayed. See [Styling Variables](https://primer.io/docs/sdk/primer-checkout-web/styling-variables.md) for a complete reference.

### Theme Builder

Preview

### Payment Details

Enter your card information

Card Number

4242 4242 4242 4242

Expiry

12/25

CVV

•••

Pay

styles.css

theme.json

Theme.kt

Theme.swift

Copy to clipboard

<pre />

## Try it live in StackBlitz

See styling in action with these interactive examples:

<table>
  <thead>
    <tr>
      <th width="200">Example</th>
      <th>Description</th>

      <th width="150" />
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>**Theme variations**</td>
      <td>Explore light, dark and more</td>

      <td>
        [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/fork/github/primer-io/examples/tree/main/examples/primer-checkout-themes)
      </td>
    </tr>

    <tr>
      <td>**Custom form styling**</td>
      <td>See custom CSS styling applied to a reordered payment form layout</td>

      <td>
        [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/fork/github/primer-io/examples/tree/main/examples/primer-checkout-custom-form)
      </td>
    </tr>
  </tbody>
</table>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.