What is your developer-dependent CMS actually costing you? Calculate your costs and get a full report
What is your developer-dependent CMS actually costing you? Calculate your costs and get a full report
How it works
How Agility Components map to Svelte components in the SvelteKit starter — the ContentZone registry, component props, and adding your own component.
Legacy — SvelteKit docs are no longer actively maintained. The SvelteKit starter targets SvelteKit 2; SvelteKit 3 shipped in October 2026. See why we recommend Next.js and .NET. If you need SvelteKit, let us know.
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.
ContentZone.svelte walks the components the editor placed in a zone and picks the right Svelte component by the model's reference name:
<!-- 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.
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:
<!-- 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.
In Agility: Models → Component Models → New — e.g. CallToAction with fields title, link. Add it to a page so there's content to render.
In code: create src/modules/agility-components/CallToAction.svelte:
<script lang="ts">
export let item: any;
const { fields: { title, link } } = item;
</script>
<a href={link.href} class="btn">{title}</a>
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.
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.