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

# UI Resources Guide

> Design patterns, accessibility, and testing for UI Resource templates

This guide covers design principles, common patterns, and testing strategies for UI Resource templates. For template syntax and configuration, see the [UI Resources reference](../features/ui-resources).

## When to Use UI Resources

UI Resources turn plain text responses into visual components. Use them when:

| Scenario             | Why it helps                                             |
| -------------------- | -------------------------------------------------------- |
| **Product displays** | Images, prices, and buttons are more effective than text |
| **Status tracking**  | Visual progress indicators are clearer than text status  |
| **Data tables**      | Structured data is easier to scan in table format        |
| **Action options**   | Buttons with clear labels improve conversion             |
| **Contact cards**    | Professional display of contact information              |

Skip UI Resources for simple text answers, speed-critical conversations, or plain-text contexts (terminal interfaces).

***

## Design Principles

### 1. Mobile-First

Templates display in chat widgets that are often mobile-sized. Start with small screens:

```css theme={null}
.card {
  width: 100%;
  padding: 16px;
}

@media (min-width: 480px) {
  .card {
    max-width: 400px;
    padding: 24px;
  }
}
```

### 2. Clear Hierarchy

Guide users' eyes to the most important information first:

```html theme={null}
<article class="product-card">
  <h2 class="product-name">{{ product_name }}</h2>        <!-- Primary -->
  <p class="product-description">{{ description }}</p>     <!-- Secondary -->
  <span class="product-sku">SKU: {{ sku }}</span>          <!-- Tertiary -->
  <a href="{{ product_url }}" class="cta-button">View</a> <!-- Action -->
</article>
```

### 3. Consistent Branding

Use CSS custom properties for your design system:

```css theme={null}
:root {
  --primary: #0069ED;
  --success: #10B981;
  --warning: #F59E0B;
  --error: #EF4444;
  --text-primary: #111827;
  --text-secondary: #6B7280;
  --border: #E5E7EB;
}
```

### 4. Graceful Degradation

Always handle missing data:

```html theme={null}
{% if product_image %}
  <img src="{{ product_image }}" alt="{{ product_name }}">
{% else %}
  <div class="image-placeholder">No image available</div>
{% endif %}

<h2>{{ product_name | default('Product') }}</h2>
```

***

## Common Patterns

### Product Card

```html theme={null}
<div class="product-card">
  {% if image_url %}
  <img src="{{ image_url }}" alt="{{ name }}" class="product-image">
  {% endif %}
  <div class="product-content">
    <h2>{{ name }}</h2>
    <p class="description">{{ description | truncate(120) }}</p>
    <div class="price-section">
      {% if original_price and original_price > price %}
      <span class="original-price">${{ original_price }}</span>
      {% endif %}
      <span class="current-price">${{ price }}</span>
    </div>
    <span class="stock-badge {{ 'in-stock' if in_stock else 'out-of-stock' }}">
      {{ 'In Stock' if in_stock else 'Out of Stock' }}
    </span>
    <a href="{{ product_url }}" class="btn-primary">View Details</a>
  </div>
</div>

<style>
  .product-card { border: 1px solid #e5e7eb; border-radius: 12px; overflow: hidden; background: white; }
  .product-image { width: 100%; height: 200px; object-fit: cover; }
  .product-content { padding: 16px; }
  .product-content h2 { font-size: 18px; font-weight: 600; margin: 0 0 8px; }
  .description { font-size: 14px; color: #6b7280; margin-bottom: 12px; }
  .original-price { text-decoration: line-through; color: #9ca3af; margin-right: 8px; }
  .current-price { font-size: 24px; font-weight: 700; color: #0069ED; }
  .stock-badge { display: inline-block; padding: 4px 8px; border-radius: 4px; font-size: 12px; margin: 12px 0; }
  .in-stock { background: #d1fae5; color: #065f46; }
  .out-of-stock { background: #fee2e2; color: #991b1b; }
  .btn-primary { display: block; width: 100%; padding: 12px; text-align: center; text-decoration: none; border-radius: 8px; background: #0069ED; color: white; font-weight: 500; }
</style>
```

### Status Card

```html theme={null}
<div class="status-card">
  <div class="status-header">
    <span class="status-label">{{ status_type | default('Status') }}</span>
    <span class="status-badge status-{{ status | lower }}">{{ status }}</span>
  </div>
  {% if reference_id %}
  <div class="reference">Reference: <strong>{{ reference_id }}</strong></div>
  {% endif %}
  {% if steps %}
  <div class="progress-steps">
    {% for step in steps %}
    <div class="step {{ 'completed' if step.completed else '' }} {{ 'current' if step.current else '' }}">
      <div class="step-dot">{% if step.completed %}✓{% else %}{{ loop.index }}{% endif %}</div>
      <div>
        <span class="step-title">{{ step.title }}</span>
        {% if step.date %}<span class="step-date">{{ step.date }}</span>{% endif %}
      </div>
    </div>
    {% endfor %}
  </div>
  {% endif %}
  {% if action_url %}
  <a href="{{ action_url }}" class="btn-secondary">{{ action_text | default('View Details') }}</a>
  {% endif %}
</div>

<style>
  .status-card { background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 12px; padding: 20px; }
  .status-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; }
  .status-label { font-size: 14px; color: #6b7280; }
  .status-badge { padding: 4px 12px; border-radius: 20px; font-size: 14px; font-weight: 500; }
  .status-pending { background: #fef3c7; color: #92400e; }
  .status-processing { background: #dbeafe; color: #1e40af; }
  .status-shipped, .status-delivered { background: #d1fae5; color: #065f46; }
  .status-cancelled { background: #fee2e2; color: #991b1b; }
  .reference { font-size: 14px; color: #6b7280; margin-bottom: 16px; }
  .step { display: flex; align-items: flex-start; margin-bottom: 12px; opacity: 0.5; }
  .step.completed, .step.current { opacity: 1; }
  .step-dot { width: 24px; height: 24px; border-radius: 50%; background: #e5e7eb; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600; margin-right: 12px; flex-shrink: 0; }
  .step.completed .step-dot { background: #10b981; color: white; }
  .step.current .step-dot { background: #0069ED; color: white; }
  .step-title { font-size: 14px; font-weight: 500; display: block; }
  .step-date { font-size: 12px; color: #6b7280; }
  .btn-secondary { display: block; width: 100%; padding: 10px; text-align: center; text-decoration: none; border: 1px solid #0069ED; color: #0069ED; border-radius: 8px; font-weight: 500; background: white; margin-top: 16px; }
</style>
```

### Action Buttons

```html theme={null}
<div class="action-container">
  {% if title %}<h3>{{ title }}</h3>{% endif %}
  {% if description %}<p class="action-desc">{{ description }}</p>{% endif %}
  <div class="action-buttons">
    {% for action in actions %}
    <a href="{{ action.url }}" class="action-btn action-{{ action.style | default('secondary') }}">
      {% if action.icon %}<span class="action-icon">{{ action.icon }}</span>{% endif %}
      <span class="action-label">{{ action.label }}</span>
      {% if action.description %}<span class="action-sublabel">{{ action.description }}</span>{% endif %}
    </a>
    {% endfor %}
  </div>
</div>

<style>
  .action-container h3 { font-size: 16px; font-weight: 600; margin: 0 0 8px; }
  .action-desc { font-size: 14px; color: #6b7280; margin-bottom: 16px; }
  .action-buttons { display: flex; flex-direction: column; gap: 8px; }
  .action-btn { display: flex; flex-direction: column; padding: 16px; border-radius: 8px; text-decoration: none; }
  .action-primary { background: #0069ED; color: white; }
  .action-secondary { background: #f3f4f6; color: #111827; }
  .action-icon { font-size: 20px; margin-bottom: 4px; }
  .action-label { font-weight: 500; }
  .action-sublabel { font-size: 12px; opacity: 0.8; margin-top: 4px; }
</style>
```

### Data Table

```html theme={null}
<div class="table-container">
  {% if title %}<h3>{{ title }}</h3>{% endif %}
  <table class="data-table">
    <thead>
      <tr>{% for header in headers %}<th>{{ header }}</th>{% endfor %}</tr>
    </thead>
    <tbody>
      {% for row in rows %}
      <tr>{% for cell in row %}<td>{{ cell }}</td>{% endfor %}</tr>
      {% else %}
      <tr><td colspan="{{ headers | length }}" class="empty-state">No data available</td></tr>
      {% endfor %}
    </tbody>
  </table>
</div>

<style>
  .table-container { overflow-x: auto; }
  .table-container h3 { font-size: 16px; font-weight: 600; margin: 0 0 12px; padding: 0 4px; }
  .data-table { width: 100%; border-collapse: collapse; font-size: 14px; }
  .data-table th, .data-table td { padding: 12px; text-align: left; border-bottom: 1px solid #e5e7eb; }
  .data-table th { background: #f9fafb; font-weight: 600; color: #374151; }
  .data-table tr:hover { background: #f9fafb; }
  .empty-state { text-align: center; color: #6b7280; padding: 24px; }
</style>
```

***

## Accessibility

### Semantic HTML

Use proper HTML elements — headings, paragraphs, lists, and `<article>` instead of generic divs:

```html theme={null}
<!-- Good -->
<article class="product-card">
  <h2>{{ product_name }}</h2>
  <p>{{ description }}</p>
  <a href="{{ url }}" role="button">Buy Now</a>
</article>
```

### Images

Always provide meaningful alt text:

```html theme={null}
<img src="{{ product_image }}" alt="{{ product_name }} - {{ product_category }}">
```

### Color Contrast

Ensure readable text and provide non-color indicators:

```css theme={null}
.error {
  color: #dc2626;
  border-left: 3px solid #dc2626; /* Visual indicator beyond color */
}
```

### Focus States

Make interactive elements keyboard-accessible:

```css theme={null}
.btn:focus, a:focus {
  outline: 2px solid #0069ED;
  outline-offset: 2px;
}
```

### Screen Readers

Add ARIA labels where visual meaning is not conveyed by text:

```html theme={null}
<div class="rating" role="img" aria-label="{{ rating }} out of 5 stars">
  {% for i in range(5) %}
  <span class="star {% if i < rating %}filled{% endif %}" aria-hidden="true">★</span>
  {% endfor %}
</div>
```

***

## Testing Templates

### Create Test Scenarios

Test with different data in the template preview:

**All data provided:**

```json theme={null}
{
  "product_name": "Premium Widget",
  "price": 99.99,
  "in_stock": true,
  "features": ["Feature A", "Feature B"]
}
```

**Minimal data (only required fields):**

```json theme={null}
{
  "product_name": "Basic Widget",
  "price": 29.99
}
```

**Edge cases:**

```json theme={null}
{
  "product_name": "A very long product name that might cause layout issues",
  "price": 1234567.89,
  "in_stock": false,
  "features": []
}
```

### Checklist

* [ ] Renders with all data provided
* [ ] Renders with only required fields
* [ ] Long text does not break the layout
* [ ] Missing images show a placeholder
* [ ] Looks correct on mobile widths
* [ ] Buttons and links are clickable
* [ ] Colors have sufficient contrast
* [ ] No external dependencies that might break

***

## Performance Tips

* **Keep templates light** — avoid loading external frameworks via CDN
* **Specify image dimensions** to prevent layout shift: `<img width="300" height="200" ...>`
* **Use `loading="lazy"`** for images below the fold
* **Include only necessary CSS** — skip unused utility classes
* **Prefer CSS over JavaScript** for interactions (hover effects, accordions via `<details>`)

***

## Related

* [UI Resources](../features/ui-resources) — Template syntax, configuration, and Jinja2 reference
* [UI Resource Tool](../tools/ui-resource-tool) — Tool configuration
* [AI Template Editor](../features/ai-template-editor) — Edit templates with natural language
