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

# Content Fields

> CMS-like editable text for non-developers

Content fields let non-technical users edit text without touching code. Headlines, descriptions, button labels—anything that might need updating can be a content field.

<Frame caption="Content fields for a landing page">
  <img src="https://mintcdn.com/tinykit/Tf0C1lubauRtpCSg/images/screenshot-landing-content.png?fit=max&auto=format&n=Tf0C1lubauRtpCSg&q=85&s=9710d9a5eb18b372855bf5f38505756f" alt="Content fields panel" width="2880" height="1636" data-path="images/screenshot-landing-content.png" />
</Frame>

## How It Works

1. The AI (or you) creates a content field with a name and value
2. The field appears in the **Content tab** with an editable input
3. Your code references the field via `import content from '$content'`
4. When someone edits the field, the preview updates instantly

```
Content Tab                          Your Code
┌─────────────────────┐              ┌─────────────────────┐
│ Hero Title          │              │ <h1>                │
│ ┌─────────────────┐ │     →        │   {content.hero_   │
│ │ Welcome to App  │ │              │    title}           │
│ └─────────────────┘ │              │ </h1>               │
└─────────────────────┘              └─────────────────────┘
```

***

## Using Content Fields

### In Your Code

```svelte theme={null}
<script>
  import content from '$content'
</script>

<h1>{content.hero_title}</h1>
<p>{content.hero_description}</p>
<button>{content.cta_button}</button>
```

### Name Conversion

Field names are converted to snake\_case:

| Field Name       | Access As                  |
| ---------------- | -------------------------- |
| Hero Title       | `content.hero_title`       |
| CTA Button Text  | `content.cta_button_text`  |
| Footer Copyright | `content.footer_copyright` |
| App Name         | `content.app_name`         |

<Tip>
  When you hover over a field in the Content tab, you'll see the exact key to use in your code.
</Tip>

### Default Values

Always provide fallbacks for robustness:

```svelte theme={null}
<h1>{content.hero_title || 'Welcome'}</h1>
<p>{content.tagline || 'Your default tagline here'}</p>
```

***

## Field Types

| Type         | Input            | Best For                    |
| ------------ | ---------------- | --------------------------- |
| **text**     | Single line      | Titles, labels, short text  |
| **textarea** | Multi-line       | Descriptions, paragraphs    |
| **number**   | Numeric input    | Prices, quantities, limits  |
| **boolean**  | Toggle switch    | Feature flags, visibility   |
| **image**    | Image upload     | Logos, photos, icons        |
| **markdown** | Rich text editor | Formatted content, articles |

### Text Fields

Single line text for titles, labels, and short content:

```svelte theme={null}
<h1>{content.page_title}</h1>
<button>{content.submit_button}</button>
```

### Textarea Fields

Multi-line text for longer content:

```svelte theme={null}
<p class="description">{content.about_text}</p>
<div class="bio">{content.author_bio}</div>
```

### Number Fields

Numeric values that can be used in calculations:

```svelte theme={null}
<p>Starting at ${content.base_price}</p>
<p>Max items: {content.max_items}</p>
```

### Boolean Fields

Toggle switches for on/off settings:

```svelte theme={null}
{#if content.show_banner}
  <div class="banner">Special offer!</div>
{/if}

{#if content.enable_dark_mode}
  <body class="dark">...</body>
{/if}
```

### Image Fields

Image uploads with automatic URL handling:

```svelte theme={null}
<script>
  import content from '$content'
</script>

<img src={content.hero_image} alt="Hero" />
<img src={content.logo} alt="Company logo" />
```

Image fields automatically convert uploaded filenames to full asset URLs.

### Markdown Fields

Rich text content with markdown formatting:

```svelte theme={null}
<script>
  import content from '$content'
</script>

<!-- Markdown is converted to HTML automatically -->
<div class="article">
  {@html content.article_body}
</div>
```

<Warning>
  Markdown fields are rendered as HTML. Only use `{@html}` with trusted content to avoid XSS risks.
</Warning>

***

## Creating Content Fields

### Via the AI

Ask the AI to create content fields:

```
Add a hero section with a title and description that I can edit without code
```

The AI will:

1. Create content fields for the text
2. Reference them in the code
3. Fields appear in the Content tab

### Via the Content Tab

1. Click **Add Content Field** at the bottom of the Content tab
2. Enter a name (e.g., "Hero Title")
3. Choose a type
4. Set an initial value
5. Optionally add a description
6. Click **Add Field**

### In Code (Advanced)

If you're editing code manually, first use the text in your code:

```svelte theme={null}
<h1>{content.new_headline}</h1>
```

Then ask the AI to create the matching field, or add it in the Content tab.

***

## Best Practices

### Use Descriptive Names

<CardGroup cols={2}>
  <Card title="Good" icon="check">
    * Hero Title
    * Navigation Home Link
    * Footer Copyright Year
    * Empty Cart Message
  </Card>

  <Card title="Avoid" icon="xmark">
    * Title
    * Text 1
    * String
    * Foo
  </Card>
</CardGroup>

### Group Related Content

Use consistent prefixes for related fields:

```
hero_title
hero_description
hero_cta_text

footer_copyright
footer_company_name
footer_email
```

### Provide Context with Descriptions

When creating fields, add descriptions to help editors:

```
Name: Hero Title
Description: Main headline on the home page (keep under 50 characters)

Name: CTA Button
Description: Call-to-action button text (e.g., "Get Started", "Try Free")
```

### Handle Missing Values

Always provide fallbacks in case a field hasn't been created yet:

```svelte theme={null}
<h1>{content.title || 'Default Title'}</h1>
<p>{content.description || ''}</p>
```

***

## Common Patterns

### Conditional Content

```svelte theme={null}
{#if content.announcement_text}
  <div class="announcement">
    {content.announcement_text}
  </div>
{/if}
```

### Lists from JSON

```svelte theme={null}
<script>
  import content from '$content'

  let nav_items = $derived(
    JSON.parse(content.nav_items || '[]')
  )
</script>

<nav>
  {#each nav_items as item}
    <a href={item.url}>{item.label}</a>
  {/each}
</nav>
```

### Dynamic Placeholders

```svelte theme={null}
<input
  type="email"
  placeholder={content.email_placeholder || 'Enter your email'}
/>
```

### Content with Design

Combine content fields with design fields:

```svelte theme={null}
<h1 style="color: var(--heading-color)">
  {content.hero_title}
</h1>
```

***

## Sharing the Content Tab

Content fields are designed for non-developers to edit. You can share access to just the Content tab without exposing the full builder:

<Note>
  A dedicated content-only editing view is planned for a future release. For now, editors access the full builder but only need to use the Content tab.
</Note>

Consider creating a guide for your content editors:

1. Log in at `yourapp.com/tinykit`
2. Click the **Content** tab
3. Edit values and see changes in the preview
4. Changes save automatically

***

## FAQ

<AccordionGroup>
  <Accordion title="Can I rename a content field?">
    Not directly in the UI. Delete the old field and create a new one with the correct name. Remember to update your code to use the new key.
  </Accordion>

  <Accordion title="What happens if I delete a field that's used in code?">
    The code will show `undefined` or your fallback value. Always use fallbacks like `{content.title || 'Default'}`.
  </Accordion>

  <Accordion title="Can I use HTML in content fields?">
    Content fields are plain text by default. For HTML, use `{@html content.rich_text}`, but be careful with user-provided content (XSS risk).
  </Accordion>

  <Accordion title="How do I make a field required?">
    tinykit doesn't enforce required fields. Use fallback values in your code to handle missing content gracefully.
  </Accordion>
</AccordionGroup>
