# UI elements catalog (/docs/build/atoms-catalog)



Everything on this page imports from `@gauntlet/ui-builder`. When you build a block, reach for these elements before writing raw React Native. They read the platform's style trees, merge theme defaults, and handle the edge cases (CDN image sizing, layout animation, link routing) you would otherwise reimplement.

<Callout type="warn" title="Prefer ui-builder for new blocks">
  Some of these elements are also re-exported from `@gauntlet/components`. For new blocks, always import from `@gauntlet/ui-builder` and prefer its elements over reaching into `@gauntlet/components` — the components library is for legacy maintenance and a few app-specific organisms.
</Callout>

## Atoms [#atoms]

The primitives. Each takes a `style` object shaped like the block config's `style` section, so merchants can restyle them without code.

### Layout and structure [#layout-and-structure]

* **`Box`** — a view with an optional background: `{ kind: 'image' | 'gradient' | 'solid' | 'none' }`. Use for any container that needs a background asset; plain containers can stay `View`s.
* **`Row` / `Column`** — flex containers, so you stop typing `flexDirection` by hand.
* **`Spacer`** — a fixed gap whose dimensions live in config.
* **`Header`** — the standard "section title + optional image + see-all link" row. Don't hand-roll a heading with a chevron.
* **`BlockSection`** — the root wrapper for a block: pass it the `useBlock` result and it renders the configured header, navigation button, and content padding for you. Most "carousel of cards" blocks should start here. (`Section` is its lower-level primitive when you need to bypass the config plumbing.)

### Content [#content]

* **`Text`** — themed text leaf; set `style.kind` to pick a typography token. Use it for every text node instead of React Native's `Text`.
* **`Image`** — responsive image that rounds widths to CDN breakpoints and adapts quality to the connection. Requires a `uri` and a width or height; returns null otherwise.
* **`Icon`** — renders a registered SVG by `iconId`, with a remote-URL fallback.
* **`HtmlRichText`** — renders an HTML string (product descriptions, rich-text metafields stored as HTML) with per-tag styles.
* **`ShopifyRichText`** — renders Shopify's rich-text JSON format (what `rich_text` metafields contain). Use `HtmlRichText` for raw HTML instead.
* **`Video`** — native MP4/HLS playback, portrait by default; all `react-native-video` props pass through.
* **`YoutubeVideo`** — thumbnail-plus-play-button YouTube embed.

### Interaction [#interaction]

* **`Button`** — pressable CTA with text, optional start/end icons, loading and disabled states, and theme kinds (`primary` / `secondary` / `tertiary`).
* **`Link`** — a pressable that routes a config link (`{ kind, value }`) through the app's navigation. Use it when the pressable is purely navigational; use `Button` when it looks like a CTA.
* **`Accordion`** — self-managed expand/collapse panel with animated layout and configurable icons. Always prefer it over a hand-rolled `Pressable` + state.

### Lists [#lists]

* **`List`** — virtualized scrolling list (FlatList under the hood). For a static handful of items, a plain `.map()` is lighter.
* **`VerticalList`** — multi-column grid with row/column separators and correct handling of a partial last row. Use for 2+ column grids.

## Helper elements [#helper-elements]

Higher-level, config-shaped compositions. Each renders a complete section from a `data` prop plus optional layout and style overrides. Use them when your block is "one of the usual sections" rather than a bespoke design.

`Cta`, `Faq`, `Media`, `MediaList`, `MediaListAccordion`, `RichTextElement` (Shopify rich text), `RichTextAccordion`, `RichTextList`, `TestimonialsList`, `TextElement`, `LinkButton`, `VideoHelperElement`, `VideoList`, `HtmlRichTextElement`, and `YoutubeVideoComponent`.

## Layout elements [#layout-elements]

The units a config-declared layout is assembled from. You will mostly meet them indirectly, since the platform instantiates them from layout config, but they are exported for blocks that render layout regions themselves:

`TextLayoutItem`, `ImageLayoutItem`, `RichTextLayoutItem`, `HtmlRichTextLayoutItem`, `AccordionLayoutItem`, `ListLayoutItem`, `LinkLayoutItem`, `LinkButtonLayoutElement`, `VideoLayoutElement`, `SpacerLayoutElement`.

## Layout-driven rendering: `Content` and `getLayoutItem` [#layout-driven-rendering-content-and-getlayoutitem]

`Content` is a block that renders whatever layout its config declares — the fully config-driven end of the spectrum, where even the structure is data. Under the hood it calls `getLayoutItem(layout, source, style, options)`, which resolves a layout tree into the layout elements above. Call `getLayoutItem` yourself when your own block needs to render a config-declared region inside otherwise hand-written UI.

## Putting it together [#putting-it-together]

A card composed from atoms, with an image, a title, and a CTA inside a padded column:

```tsx title="src/app/blocks/feature-card.tsx"
import { Button, Column, Image, Text } from '@gauntlet/ui-builder'

<Column style={settings.style?.root}>
  <Image uri={imageUrl} width={width} aspectRatio={1.5} resizeMode="cover" />
  <Text style={settings.style?.title}>{title}</Text>
  <Button
    style={settings.style?.button ?? {}}
    text={ctaText}
    onPress={handlePress}
  />
</Column>
```

Every element's style comes from the block's `style` section, so the whole card restyles from the dashboard. Copy that pattern: elements from this catalog, data and styling from config. See it in a full block in [Custom blocks](/docs/build/custom-blocks).
