# Components

> Source: https://agilitycms.com/docs/sveltekit/components

**Components** (historically called *Modules* — the API still uses that name) are the building blocks editors place into a page's content zones. Each Agility Component Model has a matching **Svelte component** in the starter that knows how to render it.

## The ContentZone registry

`ContentZone.svelte` walks the components the editor placed in a zone and picks the right Svelte component by the model's reference name:

```svelte
<!-- src/modules/ContentZone.svelte (trimmed) -->
<script lang="ts">
  import Heading from "./agility-components/Heading.svelte";
  import PostsListing from "./agility-components/PostsListing.svelte";
  import PostDetails from "./agility-components/PostDetails.svelte";
  // … the other components

  export let zone: string;
  export let data: any;

  const { page, contentItem } = data.page;
  const Components = page.zones[zone];

  // dynamic detail pages: inject the resolved content item into PostDetails
  Components.forEach((component, index) => {
    if (component.module === "PostDetails") {
      Components[index].item.fields = contentItem.fields;
    }
  });
</script>

{#each Components as component}
  {#if component.module === "Heading"}
    <Heading {...component} />
  {:else if component.module === "PostsListing"}
    <PostsListing {...component} />
  {:else if component.module === "PostDetails"}
    <PostDetails {...component} />
  {:else}
    <p>Component {component.module} not found</p>
  {/if}
{/each}
```

The fallback branch is useful during development: if an editor adds a component you haven't built yet, the page tells you instead of silently dropping it.

## Anatomy of a component

Each component receives the zone entry as props — the content is on `item.fields`, matching the fields you defined on the Component Model in Agility:

```svelte
<!-- src/modules/agility-components/Heading.svelte -->
<script lang="ts">
  export let item: any;
  const { fields: { title } } = item;
</script>

<h1 class="text-3xl font-bold mt-12 mb-6">{title}</h1>
```

That's the whole contract: **model fields in Agility → `item.fields` in Svelte.**

## Adding a new component

1. **In Agility:** *Models → Component Models → New* — e.g. `CallToAction` with fields `title`, `link`. Add it to a page so there's content to render.
2. **In code:** create `src/modules/agility-components/CallToAction.svelte`:

   ```svelte
   <script lang="ts">
     export let item: any;
     const { fields: { title, link } } = item;
   </script>

   <a href={link.href} class="btn">{title}</a>
   ```

3. **Register it** in `ContentZone.svelte` — import it and add an `{:else if component.module === "CallToAction"}` branch.

Refresh, and the component renders wherever editors place it.

## Dynamic detail components

On a dynamic page (e.g. a blog post), the API resolves the item behind the page into `contentItem`, and `ContentZone` hands its fields to `PostDetails` — so the same mechanism renders both editor-composed components and item-driven detail views. See [Content Lists](/docs/sveltekit/content-lists).

---

Index of every docs page: https://agilitycms.com/docs/llms.txt
