> For the complete documentation index, see [llms.txt](https://primo.gitbook.io/usage/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://primo.gitbook.io/usage/basic-usage/components.md).

# Components

Components are the building blocks of primo sites. They're totally self-contained (unless there's a style or field they share with other components).

## Creating a Component

{% embed url="<https://www.youtube.com/watch?v=GO4ALhphlnY&feature=youtu.be>" %}

1. Focus on a row on the page
2. Click 'Component' in the toolbar
3. Write code under the 'Code' tab, create fields under the 'Fields' tab

## Component Code

### HTML

![](https://2146102850-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI5zCYEN4cqBl6YZTet%2F-MLdJ3ZoDe-URWVOUuDZ%2F-MLdJggV_6cGnn0tPAK6%2Fimage.png?alt=media\&token=6a21505b-3c15-4c6f-a9f0-e4ca6304969a)

* See an instant preview of what your code looks like
* Use \[Handlebars]\(<https://handlebarsjs.com/>) to wire up your fields
* Use \[Emmet]\(<https://docs.emmet.io/abbreviations/syntax/>) to quickly write HTML (e.g. `div>div>h1.heading`and press Tab)

### CSS

![](https://2146102850-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI5zCYEN4cqBl6YZTet%2F-MLdJ3ZoDe-URWVOUuDZ%2F-MLdO6xAe0pKaVg0wpeF%2Fimage.png?alt=media\&token=9b123422-fa96-491f-ae4e-0d02c7893316)

* Styles are encapsulated (so if you only have one image tag in your component, you can safely select it with `img.`
* Nested styles are supported (using \[postcss-nested]\(<https://github.com/postcss/postcss-nested>))

### JavaScript

* You can import any JS modules by name with `import module from 'module-name'` , where `module-name` is the module's name on \[npm]\(<https://www.npmjs.com/>). In the background, primo turns that into a request to \[Skypack]\(<https://skypack.dev/>) that looks like

  `import module from 'https://cdn.skypack.dev/module-name'.`Skypack is a CDN that sends visitors pre-optimized packages.&#x20;
* Additional values related to the component can be found under a variable named `primo` . `primo` contains three properties:&#x20;
  * **`id`** is the component's unique ID. Typically used to select the component's node.&#x20;
  * **`data`** contains the component's field values
  * **`fields`**&#x63;ontains the component's fields

{% hint style="info" %}
Sometimes you'll need to call a function from your HTML

```
<button onclick="doSomething()">click</button>
```

To do so, you'll need to define the function globally from the component's JS&#x20;

```
window.doSomething = function() {}
```

To avoid overwriting a global function (especially when reusing a component), create a global namespace using the component's ID.&#x20;

```
window[primo.id] = {
    ...window[`component${primo.id}`] || {},
    doSomething: function() {}
}
```

And access it from the component's HTML&#x20;

```
<button onclick="{{id}}.doSomething()">click</button>
```

{% endhint %}

## Component fields

Fields let you easily change content inside HTML from the CMS side.&#x20;

### Create a field

1. From within the Component Editor, click the Fields tab
2. Add a field, selecting a field type based on the data type
   * **Repeater:** Lists
   * **Group:** Objects
   * **Content:** Markdown
   * **Switch:** Boolean&#x20;
   * **Text, Number, URL**
3. Give the new field a **label** and an **ID**
   * **Label:** Labels the input field in the CMS
   * **ID:** Used from within the component's HTML to access the field value

### Connect field to HTML

primo uses the \[Handlebars]\(<https://handlebarsjs.com/>) compiler to build HTML from field values. Once you create a field, you can access their values from within the component HTML using the field's **ID.**

{% hint style="info" %}
Some handlebars features like partials aren't supported yet
{% endhint %}

{% tabs %}
{% tab title="Repeater" %}

```markup
<!-- This assumes we created and populated a repeater field with the ID of `nav` -->
{{#each nav}}
    <a href="{{url}}">{{title}}</a>
{{/each}}
```

{% endtab %}

{% tab title="Group" %}

```markup
<div>
    <h3>{{teaser.title}}</p>
    <p>{{teaser.description}}</p>
</div>
```

{% endtab %}

{% tab title="Text" %}

```markup
<h1>{{heading}}</h1>
```

{% endtab %}

{% tab title="Image" %}

```markup
<img src="{{header.url}}" alt="{{header.alt}}" />
```

{% endtab %}

{% tab title="Number" %}

```markup
<span>{{count}}</span>
```

{% endtab %}

{% tab title="Content" %}

```markup
<!-- Since this field produces html, we'll need to wrap it in three brackets -->
<!-- 'primo-copy' gives the div the same copy styles as copy rows on the page -->
<div class="primo-copy">
    {{{ page_content }}}
</div>
```

{% endtab %}

{% tab title="Switch" %}

```markup
{{#if show_contact}}
  <address>
    <a href="mailto:jon@doe.com">jon@doe.com</a><br>
    <a href="tel:+13115552368">(311) 555-2368</a>
  </address>
{{else}}
  <h1>Unfortunately, we're currently unavailable for hire</h1>
{{/if}}
```

{% endtab %}

{% tab title="URL" %}

```markup
<a href="{{detail_url}}">See More Details</a>
```

{% endtab %}

{% tab title="Link" %}

```
<a href="{{cta.url}}">{{cta.title}}</a>
```

{% endtab %}
{% endtabs %}
