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

# Field Types

> Complete reference of all available field types for blocks and pages.

Fields are what make blocks editable. You attach fields to your blocks, and editors can fill them in without touching code. This reference covers all available field types in Primo.

<Info>
  Fields can be added to three places:

  * **Sites** - Site-wide content (logo, navigation, footer, etc.)
  * **Page Types** - Page-level metadata (title, author, publish date, etc.)
  * **Blocks** - Section-level content (headlines, images, descriptions, etc.)

  Most field types work the same in all contexts, with some exceptions noted below.
</Info>

## Text Fields

<Accordion title="Text">
  Text input that automatically grows to accommodate content.

  **Use for:**

  * Headlines and titles
  * Button labels
  * Short descriptions
  * Names

  **Component usage:**

  ```svelte theme={null}
  <h1>{headline}</h1>
  <p>{description}</p>
  ```
</Accordion>

<Accordion title="Rich Text">
  WYSIWYG editor for formatted text with HTML output.

  **Use for:**

  * Article content
  * Descriptions with formatting
  * Long-form content
  * Any text needing formatting

  **Component usage:**

  ```svelte theme={null}
  <div class="content">
    {@html content}
  </div>
  ```

  <Warning>
    Rich text fields output HTML. Always use `{@html}` in your component to render it. To style the HTML content, use `:global()` in your CSS to target elements inside the rendered HTML. Use a unique class name on the wrapper to avoid affecting other styles on the page.
  </Warning>
</Accordion>

<Accordion title="Markdown">
  Markdown editor for formatted text.

  **Use for:**

  * Documentation
  * Blog posts
  * README content
  * Developer-friendly content

  **Component usage:**

  ```svelte theme={null}
  <!-- Primo processes markdown automatically -->
  <div class="markdown-content">
    {@html content}
  </div>

  <style>
    /* Use :global() to style rendered HTML */
    /* Use a unique class to avoid affecting other elements */
    .markdown-content :global(h1) {
      font-size: 2rem;
    }
    .markdown-content :global(p) {
      margin-bottom: 1rem;
    }
  </style>
  ```
</Accordion>

## Number Fields

<Accordion title="Number">
  Numeric input for integers.

  **Use for:**

  * Quantities
  * Counts
  * Whole number ratings
  * Integer values

  **Component usage:**

  ```svelte theme={null}
  <p>Quantity: {quantity}</p>
  <p>Rating: {rating}/5</p>
  ```
</Accordion>

<Accordion title="Date">
  Date picker that outputs dates in YYYY-MM-DD format.

  **Use for:**

  * Publication dates
  * Event dates
  * Deadlines
  * Any calendar dates

  **Component usage:**

  ```svelte theme={null}
  <!-- Raw YYYY-MM-DD format -->
  <time datetime={publish_date}>{publish_date}</time>

  <!-- Formatted for display -->
  <time datetime={publish_date}>
    {new Date(publish_date).toLocaleDateString()}
  </time>

  <!-- Custom formatting -->
  <time datetime={publish_date}>
    {new Date(publish_date).toLocaleDateString('en-US', {
      year: 'numeric',
      month: 'long',
      day: 'numeric'
    })}
  </time>
  ```

  <Info>
    The Date field outputs a string in YYYY-MM-DD format (e.g., "2024-01-15"). Use JavaScript's `new Date()` constructor to parse and format it for display. The raw value is perfect for the `datetime` attribute in `<time>` elements.
  </Info>
</Accordion>

## Selection Fields

<Accordion title="Select">
  Dropdown menu for selecting one option from a list.

  **Use for:**

  * Categories
  * Variants
  * Status options
  * Single-choice selections

  **Component usage:**

  ```svelte theme={null}
  <span class="category">{category}</span>
  ```

  **Options:**

  Each option in a Select field has three properties:

  * **value**: The actual value stored (used in your code)
  * **label**: Display text shown to editors
  * **icon**: Optional icon identifier (from Iconify)

  The first option in the list is used as the default value.
</Accordion>

<Accordion title="Toggle">
  Boolean toggle switch for on/off options.

  **Use for:**

  * Feature toggles
  * Boolean settings
  * Show/hide options
  * Enable/disable states

  **Component usage:**

  ```svelte theme={null}
  {#if show_cta}
    <button>Click me</button>
  {/if}
  ```
</Accordion>

<Accordion title="Slider">
  Slider for selecting numeric values.

  **Use for:**

  * Opacity values
  * Percentage selections
  * Adjustable numeric settings

  **Component usage:**

  ```svelte theme={null}
  <div style="opacity: {opacity}">
    Content with adjustable opacity
  </div>
  ```
</Accordion>

## Media Fields

<Accordion title="Image">
  Image upload and selection field. Returns an object with `url` and `alt` properties.

  **Use for:**

  * Photos
  * Graphics
  * Custom icons
  * Any visual content

  **Component usage:**

  ```svelte theme={null}
  {#if image}
    <img src={image.url} alt={image.alt} />
  {/if}
  ```

  **Options (both optional):**

  * **Max Size MB**: Maximum file size in megabytes
  * **Max Width or Height**: Maximum dimension (width or height) in pixels

  <Tip>
    The image field includes a Description input for alt text. Editors should fill this out, and developers should use `image.alt` in their components for accessibility.
  </Tip>
</Accordion>

<Accordion title="Icon">
  Icon picker for selecting icons from [Iconify](https://icon-sets.iconify.design/). Returns an SVG string.

  **Use for:**

  * Feature icons
  * UI elements
  * Decorative icons
  * Navigation icons

  **Component usage:**

  ```svelte theme={null}
  <!-- Wrap in a div for styling with font-size and color -->
  <div class="icon">
    {@html icon}
  </div>

  <style>
    .icon {
      font-size: 2rem;
      color: var(--primary-color);
    }
  </style>
  ```

  <Tip>
    For UI icons that should stay consistent across your site, consider creating a site field containing icon values. This lets you update icons site-wide from one place instead of editing individual blocks.
  </Tip>
</Accordion>

## Link Fields

<Accordion title="Link">
  Link field for both internal and external links. Returns an object with `url` and `label` properties.

  **Use for:**

  * Navigation items
  * Call-to-action buttons
  * Any clickable links

  **Component usage:**

  ```svelte theme={null}
  <a href={link.url}>{link.label}</a>
  ```
</Accordion>

<Accordion title="URL">
  Simple URL input field.

  **Use for:**

  * External URLs
  * Web addresses
  * API endpoints
  * Any URL string

  **Component usage:**

  ```svelte theme={null}
  <a href={website_url} target="_blank">Visit Website</a>
  ```
</Accordion>

## Relational Fields

<Accordion title="Site Field">
  Reference site-wide content fields. The site field references the complete value of the site field, regardless of its type.

  **Use for:**

  * Displaying site-wide content in blocks
  * Reusing global content across pages
  * Referencing branding elements

  **Component usage:**

  ```svelte theme={null}
  <!-- If the site has a "logo" image field -->
  <img src={logo.url} alt={logo.alt} />

  <!-- If the site has a "company_name" text field -->
  <h1>{company_name}</h1>
  ```

  <Note>
    Available in page types and blocks to reference site-wide content.
  </Note>

  <Info>
    When you edit a site field from the block form view, it updates the value site-wide across all blocks that reference it. Site fields cannot be edited inline on the page yet.
  </Info>
</Accordion>

<Accordion title="Page Field">
  Reference page-level fields from the current page. The page field references the complete value of the page field, regardless of its type.

  **Use for:**

  * Displaying page title in blocks
  * Showing page metadata in blocks

  **Component usage:**

  ```svelte theme={null}
  <!-- If the page has a "title" text field -->
  <h1>{title}</h1>

  <!-- If the page has a "featured_image" image field -->
  <img src={featured_image.url} alt={featured_image.alt} />
  ```

  <Note>
    Available in blocks to reference page-level content.
  </Note>

  <Info>
    When you edit a page field from the block form view, it updates the value for that specific page across all blocks that reference it. For example, if a blog post has a `featured_image` page field, changing it might update the image in the page's header block, the meta tags in the head, and on the articles list page—all from one edit (if integrated in those places).
  </Info>

  <Note>
    Page fields cannot be edited inline on the page yet.
  </Note>
</Accordion>

<Accordion title="Page">
  Select a specific page from a list. You must specify a page type to limit which pages appear in the selection list.

  **Use for:**

  * Article author (Person page type)
  * Featured article (Blog Post page type)
  * Related pages

  **Component usage:**

  ```svelte theme={null}
  <!-- Access page fields like title or custom fields -->
  <a href={author._meta.url}>
    <h3>{author.name}</h3>
    <p>{author.bio}</p>
  </a>
  ```

  The `_meta` property provides:

  * `_meta.url`: Page URL for linking
  * `_meta.slug`: Page slug
  * `_meta.name`: Page name

  **Options:**

  * **Page Type**: Required. Specifies which page type to select from (e.g., "Person", "Blog Post")
</Accordion>

<Accordion title="Page List">
  Automatically outputs all pages of a specified page type. Editors cannot select which pages to include—it returns all pages of the given type.

  **Use for:**

  * Team member listings (all Person pages)
  * Blog index (all Blog Post pages)
  * Automatic page lists

  **Component usage:**

  ```svelte theme={null}
  <div class="team">
    {#each members as member}
      <a href={member._meta.url}>
        <h3>{member.name}</h3>
        <p>{member.title}</p>
      </a>
    {/each}
  </div>
  ```

  **Options:**

  * **Page Type**: Required. Specifies which page type to output (e.g., "Person", "Blog Post")

  <Info>
    If you want editors to choose specific pages, use a **Repeater field** with nested **Page fields** instead. For selection by exclusion, combine a Page List with a Repeater > Page field.
  </Info>
</Accordion>

## Structured Fields

<Accordion title="Repeater">
  Repeatable group of fields.

  **Use for:**

  * Feature lists
  * Testimonials
  * FAQ items
  * Image galleries
  * Card grids

  **Component usage:**

  ```svelte theme={null}
  <ul>
    {#each features as feature}
      <li>
        <img src={feature.icon.url} alt={feature.icon.alt} />
        <h3>{feature.title}</h3>
        <p>{feature.description}</p>
      </li>
    {/each}
  </ul>

  <!-- Or with destructuring -->
  <ul>
    {#each features as { icon, title, description }}
      <li>
        <img src={icon.url} alt={icon.alt} />
        <h3>{title}</h3>
        <p>{description}</p>
      </li>
    {/each}
  </ul>
  ```

  <Tip>
    Avoid naming your loop variable the same as a nested field. For example, if you have a nested `link` field, use `{#each links as item}` instead of `{#each links as link}` to prevent confusion when accessing `item.link.url`.
  </Tip>

  <Example>
    A "Features" block might use a repeater named `features` with fields: `title` (Text), `description` (Text), and `icon` (Image). Editors can add multiple features, and each gets the same set of fields.
  </Example>
</Accordion>

<Accordion title="Group">
  Group of related fields displayed together.

  **Use for:**

  * Contact form (inputs + endpoint + submit\_label)
  * Card content (title + description + cta\_link)
  * Author info (name + bio + photo)

  **Component usage:**

  ```svelte theme={null}
  <div class="author">
    <img src={author.photo.url} alt={author.photo.alt} />
    <h3>{author.name}</h3>
    <p>{author.bio}</p>
  </div>
  ```
</Accordion>

## Utility Fields

<Accordion title="Info">
  Display-only field for showing helpful information to editors. Supports Markdown formatting and does not store any data—it only displays content in the editor interface.

  **Use for:**

  * Instructions for complex fields
  * Explanatory notes about content requirements
  * Documentation for editors

  <Tip>
    Consider combining Info fields with conditions to show context-specific help. For example, add an Info field that only appears when "Custom Layout" is selected from a Select field, explaining the custom layout options.
  </Tip>
</Accordion>

## Field Configuration

All fields share these base properties:

* **Type**: The field type (text, image, select, etc.)
* **Label**: Display name shown to editors
* **Key**: The variable name used in your component code

### Field-Specific Options

Some field types have additional configuration options:

**Select:**

* **Options**: Array of choices, each with value, label, and optional icon

**Image:**

* **Max Size (MB)**: Maximum file size in megabytes
* **Max Dimension (px)**: Maximum dimension (width or height) in pixels

**Page / Page List:**

* **Page Type**: Restrict selection to a specific page type

### Conditional Display

Fields can be conditionally shown or hidden based on other field values. Conditions are primarily designed for Select and Toggle fields, but also work with Text, URL, and Number fields.

When you add a condition ("Show if"):

* **Field**: Select which field to check (must be a preceding field at the same level)
* **Comparison**: Choose "Equals" or "Doesn't equal" (≠)
* **Value**: The value to compare against

<Info>
  Conditional fields help create dynamic editing interfaces that show relevant fields based on other selections. For example, to show an image field only when a "Show Image" toggle is enabled, the "Show Image" toggle must come first in the field list, then the image field below it with the condition. Fields can only reference fields that appear before them in the list.
</Info>

## Best Practices

### 1. Choose the Right Field Type

Match field types to their purpose:

* ✅ Text for headlines
* ✅ Rich Text for formatted content
* ✅ Image for photos
* ✅ Select for categories
* ❌ Text for long articles (use Rich Text)
* ❌ Number for phone numbers (use Text)

### 2. Provide Defaults

Fields in Primo are globally available in your block code, but you should always handle empty/missing values:

```svelte theme={null}
<!-- Good: Handles empty values -->
{#if headline}
  <h1>{headline}</h1>
{/if}

{#if show_cta}
  <button>Click me</button>
{/if}

<!-- Also good: Use default values with OR -->
<h1>{headline || "Welcome"}</h1>
```

### 3. Use Helpful Labels

Clear labels help editors understand fields:

* ✅ "Featured Image"
* ✅ "Publication Date"
* ✅ "Author Name"
* ❌ "Field 1"
* ❌ "Data"

### 4. Add Help Text

Help text guides editors:

<Example>
  **Field**: "Featured Image"
  **Help text**: "This image appears at the top of the post and in social media shares. Recommended size: 1200x630px."
</Example>

## Field Combinations

### Common Patterns

**Hero Block:**

* `headline` (Text)
* `subheadline` (Text)
* `cta` (Link)
* `background_image` (Image, optional)

```svelte theme={null}
<section>
  {#if background_image?.url}
    <img src={background_image.url} alt={background_image.alt} class="background" />
  {/if}
  <h1>{headline}</h1>
  <p>{subheadline}</p>
  {#if cta?.url}
    <a href={cta.url}>{cta.label}</a>
  {/if}
</section>
```

**Card Block:**

* `title` (Text)
* `description` (Rich Text)
* `image` (Image, optional)
* `link` (Link, optional)

```svelte theme={null}
<div class="card">
  {#if image?.url}
    <img src={image.url} alt={image.alt} />
  {/if}
  <h3>{title}</h3>
  <div class="description">{@html description}</div>
  {#if link?.url}
    <a href={link.url}>{link.label}</a>
  {/if}
</div>
```

**Feature List:**

* `features` (Repeater) with:
  * `title` (Text)
  * `description` (Text)
  * `icon` (Image, optional)

```svelte theme={null}
<ul class="features">
  {#each features as feature}
    <li>
      {#if feature.icon?.url}
        <img src={feature.icon.url} alt={feature.icon.alt} />
      {/if}
      <h3>{feature.title}</h3>
      <p>{feature.description}</p>
    </li>
  {/each}
</ul>
```

**Employees of the Month (editor selects):**

* `employees` (Repeater) with:
  * `employee` (Page, limited to "Person" page type)

```svelte theme={null}
<div class="employees">
  {#each employees as { employee }}
    <a href={employee._meta.url}>
      <h3>{employee.name}</h3>
      <p>{employee.title}</p>
    </a>
  {/each}
</div>
```

**Filtered Page List (selection by exclusion):**

* `all_team` (Page List, "Person" page type)
* `excluded_members` (Repeater) with:
  * `member` (Page, limited to "Person" page type)

```svelte theme={null}
<script>
  // Filter out excluded members
  const displayed_team = all_team.filter(person =>
    !excluded_members.some(({ member }) => member._meta.slug === person._meta.slug)
  )
</script>

<div class="team">
  {#each displayed_team as person}
    <a href={person._meta.url}>
      <h3>{person.name}</h3>
      <p>{person.title}</p>
    </a>
  {/each}
</div>
```

<Tip>
  Start with simple field types (Text, Image, Link) and add complexity (Repeaters, Groups) as you need it. Most blocks only need a few well-chosen fields.
</Tip>

## Next Steps

<CardGroup cols={2}>
  <Card title="Working with Fields" icon="pen-to-square" href="/building-sites/working-with-fields">
    Learn how to add fields to your components.
  </Card>

  <Card title="Writing Components" icon="code" href="/building-sites/writing-components">
    See how fields work in component code.
  </Card>

  <Card title="Defining Page Types" icon="layer-group" href="/building-sites/defining-page-types">
    Use fields in page type configuration.
  </Card>

  <Card title="Building from Scratch" icon="rocket" href="/building-sites/your-first-site">
    See fields in action with real examples.
  </Card>
</CardGroup>
