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

# Design

> Customize colors, fonts, spacing, and other visual properties to match your brand.

Swish uses design tokens to control the visual appearance of every UI component. Pass tokens under `ui.design`, and the values are applied across the drawer, dialogs, buttons, and all other surfaces.

```js theme={null}
window.SwishOptions = {
  ui: {
    design: {
      colors: {
        primaryButtonBackgroundRgb: "22 163 74",
      },
      typography: {
        headingFontFamily: "'Playfair Display', serif",
      },
      rounding: {
        borderRadiusScale: 0.5,
      },
    },
  },
};
```

## Colors

Tokens ending in `Rgb` take space-separated RGB triplets without the `rgb()` wrapper (e.g. `"22 163 74"`). Swish uses the raw values internally so it can apply opacity variations. `overlayBackground` and `savedIconColor` are plain CSS colors instead - pass any valid value (`"rgba(0, 0, 0, 0.4)"`, `"#ffffff"`).

```js theme={null}
ui: {
  design: {
    colors: {
      backgroundRgb: "255 255 255",
      textColorRgb: "15 23 42",
      headingColorRgb: "15 23 42",
      primaryButtonBackgroundRgb: "22 163 74",
      primaryButtonColorRgb: "255 255 255",
    },
  },
}
```

| Token | Description |
| - | - |
| `backgroundRgb` | Drawer background color. Sheets, toasts and form controls paint the same value, and the border and skeleton colors are mixed from it. |
| `textColorRgb` | Primary text color. |
| `textColorDangerRgb` | Danger/error text color. |
| `headingColorRgb` | Heading text color. |
| `primaryButtonBackgroundRgb` | Primary button background. |
| `primaryButtonColorRgb` | Primary button text color. |
| `neutralButtonBackgroundRgb` | Neutral button background. |
| `neutralButtonColorRgb` | Neutral button text color. |
| `dangerButtonBackgroundRgb` | Danger button background. |
| `dangerButtonColorRgb` | Danger button text color. |
| `statusDotBackgroundRgb` | Notification status dot color. |
| `badgeBackgroundRgb` | Badge background color. |
| `badgeColorRgb` | Badge text color. |
| `overlayBackground` | Overlay backdrop color (e.g. `"rgba(0, 0, 0, 0.4)"`). |
| `savedIconColor` | Color of the save button icon when an item is saved. See [Save button](#save-button) for its unsaved counterpart and the other save button tokens. |

> [!TIP]
>
> To convert a hex color like `#16A34A` to an RGB triplet for the `*Rgb` tokens,
> drop the hash and convert each pair to decimal: `22 163 74`. Don't do this for
> `overlayBackground` or `savedIconColor` - they take the hex value as-is.

## Typography

Typography tokens let you align Swish text with your store's typeface and sizing. Tokens are grouped by text role: headings, body text, buttons, and badges.

```js theme={null}
ui: {
  design: {
    typography: {
      headingFontFamily: "'Playfair Display', serif",
      headingTextTransform: "uppercase",
      headingFontWeight: 700,
      textFontFamily: "'Inter', sans-serif",
      textFontSize: 14,
      buttonFontFamily: "'Inter', sans-serif",
      buttonTextTransform: "uppercase",
      buttonLetterSpacing: "0.05em",
    },
  },
}
```

Each role supports the same set of properties:

| Suffix | Type | Description |
| - | - | - |
| `FontFamily` | `string` | CSS font family value. |
| `FontSize` | `number \| string` | Font size. Numbers are treated as pixels. |
| `FontWeight` | `number \| string` | Font weight. |
| `LineHeight` | `number \| string` | Line height. |
| `LetterSpacing` | `string` | Letter spacing (e.g. `"0.05em"`). |
| `TextTransform` | `string` | CSS text transform (e.g. `"uppercase"`). |

Prefix with `heading`, `text`, `button`, or `badge` to target a specific role. For example, `headingFontFamily` sets the heading font while `buttonFontFamily` sets the button font.

> [!NOTE]
>
> Body text also has a `textLineHeightParagraph` token for longer text blocks
> like product descriptions.

## Rounding

Control border radii across the UI. The `borderRadiusScale` token acts as a global multiplier - set it to `0` for sharp corners or increase it for rounder shapes.

```js theme={null}
ui: {
  design: {
    rounding: {
      borderRadiusScale: 0,
    },
  },
}
```

For finer control, override individual component radii:

| Token | Description |
| - | - |
| `borderRadiusScale` | Global multiplier for all border radii. |
| `buttonBorderRadius` | Border radius for buttons. |
| `iconButtonBorderRadius` | Border radius for icon-only buttons. |
| `dialogBorderRadius` | Border radius for dialogs. |
| `formInputBorderRadius` | Border radius for form inputs. |
| `imageCardBorderRadius` | Border radius for product card images. |
| `imageSliderBorderRadius` | Border radius for image sliders. |
| `thumbnailBorderRadius` | Border radius for thumbnails. |
| `badgeBorderRadius` | Border radius for badges. |

## Sizes

Size tokens control the dimensions of buttons, icons, and images.

```js theme={null}
ui: {
  design: {
    sizes: {
      buttonHeight: 44,
      iconSize: 20,
      imageCardAspectRatio: "3/4",
    },
  },
}
```

| Token | Type | Description |
| - | - | - |
| `buttonHeight` | `number \| string` | Height of primary buttons. |
| `iconButtonSize` | `number \| string` | Size of icon-only buttons. |
| `formInputHeight` | `number \| string` | Height of form inputs. |
| `iconSize` | `number \| string` | Default icon size. |
| `imageCardAspectRatio` | `string` | Aspect ratio for product card images (e.g. `"3/4"`). |
| `imageSliderAspectRatio` | `string` | Aspect ratio for image sliders. |
| `thumbnailAspectRatio` | `string` | Aspect ratio for thumbnails (notifications, toasts, order items). |
| `imageFit` | `string` | How product card, gallery card and image slider images fill their frame: `"cover"` (default, crops) or `"contain"` (shows the whole image). |

## Component tokens

Component tokens give you fine-grained control over specific UI elements, so you only need to set them when a component should differ from the global style.

Some derive from the global tokens above (for example `productCardTitleColor` and `optionPillBackground` resolve to `textColorRgb` and `neutralButtonBackgroundRgb`), but others carry their own default - product card titles are deliberately smaller and bolder than body text. Each table below states the default that applies.

### Product card

Control the appearance of product titles on grid cards.

```js theme={null}
ui: {
  design: {
    productCard: {
      productCardTitleFontSize: 12,
      productCardTitleFontWeight: 400,
      productCardTitleColor: "#333",
    },
  },
}
```

| Token | Type | Description |
| - | - | - |
| `productCardTitleFontSize` | `number \| string` | Font size for product card titles. Defaults to `12px`, independent of `textFontSize`. |
| `productCardTitleFontWeight` | `number \| string` | Font weight for product card titles. Defaults to `500`, independent of `textFontWeight`. |
| `productCardTitleColor` | `string` | Text color for product card titles. Defaults to `textColorRgb`. |

### Navigation

Style the bottom navigation bar in the drawer.

```js theme={null}
ui: {
  design: {
    navigation: {
      navBackground: "rgb(240, 240, 240)",
      navShadow: "none",
      navLabelTextTransform: "uppercase",
      navLabelLetterSpacing: "1px",
      navActiveIndicatorColor: "#333",
    },
  },
}
```

| Token | Type | Description |
| - | - | - |
| `navHeight` | `number \| string` | Height of the navigation bar. |
| `navBackground` | `string` | Background color of the docked navigation bar. |
| `navShadow` | `string` | Box shadow for the navigation bar. |
| `navLabelFontSize` | `number \| string` | Font size for navigation labels. |
| `navLabelTextTransform` | `string` | Text transform for navigation labels. |
| `navLabelLetterSpacing` | `string` | Letter spacing for navigation labels. |
| `navActiveIndicatorColor` | `string` | Color of the active tab indicator. |

### Option pill

Customize the variant selector pills on the product detail view.

```js theme={null}
ui: {
  design: {
    optionPill: {
      optionPillBackground: "#fff",
      optionPillBorderColor: "#ccc",
      optionPillSelectedBackground: "#333",
      optionPillSelectedColor: "#fff",
      optionPillSelectedBorderColor: "#333",
    },
  },
}
```

| Token | Type | Description |
| - | - | - |
| `optionPillBackground` | `string` | Background color of unselected pills. |
| `optionPillBorderColor` | `string` | Border color of unselected pills. |
| `optionPillFontSize` | `number \| string` | Font size for pill labels. |
| `optionPillPadding` | `number \| string` | Inner padding for pill labels. |
| `optionPillSelectedBackground` | `string` | Background color of the selected pill. |
| `optionPillSelectedColor` | `string` | Text color of the selected pill. |
| `optionPillSelectedBorderColor` | `string` | Border color of the selected pill. |
| `optionPillHeight` | `number \| string` | Height of the pills. |
| `optionPillBorderRadius` | `string` | Border radius of the pills. |

### Drawer

Control the drawer panel dimensions.

```js theme={null}
ui: {
  design: {
    drawer: {
      drawerWidth: 520,
      drawerMobileTopOffset: 60,
    },
  },
}
```

| Token | Type | Description |
| - | - | - |
| `drawerWidth` | `number \| string` | Width of the drawer on desktop viewports. |
| `drawerMobileTopOffset` | `number \| string` | Space between the top of the viewport and the drawer on mobile. |

### Save button

A placed save button comes in two looks, each with its own settings. **On image** is for buttons over product media - collection cards and image corners: an icon-only chip. **On page** is for buttons in the page flow - under **Add to cart** or in your theme's button row: a heart with its label. Editing one look never changes the other. A placement picks its look with [`style`](https://swish.app/docs/references/sdk/placements#style), and collection placements are always On image. The hearts in the drawer and on the wishlist page follow the On image settings.

Colors are plain CSS colors, so pass any valid value (`"rgba(0, 0, 0, 0.15)"`, `"#ff0000"`). A token you leave unset keeps the look's preset: On image is a `#121212` heart on a white chip, filled once the item is saved; On page is a white heart and label on `#121212`, the heart filled once saved.

```js theme={null}
ui: {
  design: {
    saveButtonOnImage: {
      saveButtonOnImageIconColor: "rgb(255, 0, 0)",
      saveButtonOnImageBackground: "rgba(255, 255, 255, 0.9)",
    },
    saveButtonOnPage: {
      saveButtonOnPageBackground: "#1a1a1a",
      saveButtonOnPageColor: "#ffffff",
    },
  },
}
```

#### On image

| Token | Type | Description |
| - | - | - |
| `saveButtonOnImageIconColor` | `string` | Icon outline color before an item is saved. Defaults to `#121212`. |
| `saveButtonOnImageSavedIconColor` | `string` | Icon outline color once an item is saved. Defaults to `#121212`. |
| `saveButtonOnImageIconFill` | `string` | Color inside the icon outline before an item is saved. Defaults to no fill. |
| `saveButtonOnImageSavedIconFill` | `string` | Color inside the icon outline once an item is saved. Defaults to the outline color. |
| `saveButtonOnImageBackground` | `string` | Chip behind the icon before an item is saved. Defaults to `#ffffff`. |
| `saveButtonOnImageSavedBackground` | `string` | Chip behind the icon once an item is saved. Defaults to `#ffffff`. The drawer and wishlist page hearts fall back to `saveButtonOnImageBackground` when it's not set. |
| `saveButtonOnImageBackgroundSize` | `number \| string` | Diameter of the chip. Numbers are treated as pixels. Defaults to `32px`. |
| `saveButtonOnImageIconSize` | `number \| string` | Size of the icon. Numbers are treated as pixels. Defaults to `20px`. |
| `saveButtonOnImageIconThickness` | `number \| string` | Stroke width of the icon outline on placed buttons. Numbers are treated as pixels. Defaults to `1.2px`. |

#### On page

| Token | Type | Description |
| - | - | - |
| `saveButtonOnPageColor` | `string` | Label and icon outline color before an item is saved. Defaults to `#ffffff`. |
| `saveButtonOnPageSavedColor` | `string` | Label and icon outline color once an item is saved. Defaults to `#ffffff`. |
| `saveButtonOnPageIconFill` | `string` | Color inside the icon outline before an item is saved. Defaults to no fill. |
| `saveButtonOnPageSavedIconFill` | `string` | Color inside the icon outline once an item is saved. Defaults to the outline color. |
| `saveButtonOnPageBackground` | `string` | Button background before an item is saved. Defaults to `#121212`. |
| `saveButtonOnPageSavedBackground` | `string` | Button background once an item is saved. Defaults to `#121212`. |
| `saveButtonOnPageIconSize` | `number \| string` | Size of the icon. Numbers are treated as pixels. Defaults to `20px`. |
| `saveButtonOnPageIconThickness` | `number \| string` | Stroke width of the icon outline. Numbers are treated as pixels. Defaults to `1.2px`. |

An on page button takes its height from the standard button tokens and its corners from the rounding tokens above, so it sits in your theme's button row like one of its own. A placement's own fill and size settings take priority over these tokens where they overlap. To swap the heart for another glyph, set `ui.icons.save` to your own SVG - the glyph is shared by both looks - see [Icons](https://swish.app/docs/guides/customize/appearance/icons.md) for the format. To animate a save, set [`ui.saveButton.animation`](https://swish.app/docs/references/sdk/configuration#save-button), which every save button plays whatever its look.

### Image slider

| Token | Type | Description |
| - | - | - |
| `imageSliderDotColorSelected` | `string` | Color of the active pagination dot. |

```js theme={null}
ui: {
  design: {
    imageSlider: {
      imageSliderDotColorSelected: "#333",
    },
  },
}
```

## Further reading

* [Full defaults reference](https://swish.app/docs/guides/customize/defaults.md) for every token with its default value
* [Custom CSS](https://swish.app/docs/guides/customize/appearance/css.md) for changes beyond design tokens
* [Icons](https://swish.app/docs/guides/customize/appearance/icons.md) to replace built-in icons


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