# Layout Customization

Source: https://www.potatoannotator.com/docs/features/layout-customization

*New in v2.1.0*

Potato provides two approaches for customizing the annotation interface layout:

1. **Auto-generated layouts**: Potato generates an HTML layout file that you can edit
2. **Custom layout files**: Create your own HTML template with full control over styling

## Quick Start

### Using Auto-generated Layouts

1. Run your server once — Potato creates `layouts/task_layout.html`
2. Edit the generated file to customize styling
3. Your changes persist across server restarts (unless you modify `annotation_schemes` in the config)

### Using Custom Layout Files

1. Create your layout file (e.g., `layouts/custom_task_layout.html`)
2. Reference it in your config:

```yaml
task_layout: layouts/custom_task_layout.html
```

## Layout File Structure

A custom layout file must include:

```html
<style>
    /* Your custom CSS */
</style>

<div class="annotation_schema">
    <!-- Your annotation forms -->
    <form id="schema_name" class="annotation-form radio" data-annotation-id="0">
        <fieldset schema="schema_name">
            <legend>Question text</legend>
            <!-- Input elements -->
        </fieldset>
    </form>
</div>
```

### Required Form Attributes

Each annotation scheme needs:

| Attribute | Description |
|-----------|-------------|
| `id` | Must match the `name` in your config's `annotation_schemes` |
| `class` | Include `annotation-form` and the type (e.g., `radio`, `multiselect`) |
| `data-annotation-id` | Sequential index (0, 1, 2...) |
| `schema` | Attribute on fieldset and inputs matching the schema name |

### Required Input Attributes

```html
<input class="schema_name annotation-input"
       type="radio"
       name="schema_name"
       value="label_value"
       schema="schema_name"
       label_name="label_value"
       onclick="onlyOne(this);registerAnnotation(this);">
```

## Example Layouts

Potato includes three example layouts demonstrating advanced customization:

### 1. Content Moderation Dashboard

**Location**: `project-hub/layout-examples/content-moderation/`

Features a warning banner header with content metadata, 2-column grid for violation categories, color-coded severity levels, and a professional moderation workflow.

```bash
python -m potato start project-hub/layout-examples/content-moderation/config.yaml -p 8000
```

### 2. Customer Service Dialogue QA

**Location**: `project-hub/layout-examples/dialogue-qa/`

Features a case header with metadata badges, grouped assessment sections, circular Likert-scale ratings, quality issues checklist, and color-coded resolution indicators.

```bash
python -m potato start project-hub/layout-examples/dialogue-qa/config.yaml -p 8000
```

### 3. Medical Image Review

**Location**: `project-hub/layout-examples/medical-review/`

Features professional medical UI styling, two-column layout for location/severity, grouped findings sections, structured medical reporting, and recommendation cards with descriptions.

```bash
python -m potato start project-hub/layout-examples/medical-review/config.yaml -p 8000
```

## CSS Techniques

### Grid Layouts

Create multi-column layouts:

```css
.annotation-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 16px;
}

.full-width {
    grid-column: 1 / -1;
}

@media (max-width: 768px) {
    .annotation-grid {
        grid-template-columns: 1fr;
    }
}
```

### Color-Coded Options

Style radio buttons with severity colors:

```css
.severity-option input[type="radio"] {
    position: absolute;
    opacity: 0;
}

.severity-label {
    display: block;
    padding: 10px;
    border-radius: 6px;
    border: 2px solid transparent;
    cursor: pointer;
    transition: all 0.2s;
}

/* Green for "None" */
.severity-none .severity-label {
    background: #dcfce7;
    color: #166534;
}
.severity-none input:checked + .severity-label {
    background: #22c55e;
    color: white;
}

/* Red for "Severe" */
.severity-severe .severity-label {
    background: #fee2e2;
    color: #991b1b;
}
.severity-severe input:checked + .severity-label {
    background: #ef4444;
    color: white;
}
```

### Section Styling

Create visual groupings:

```css
.annotation-section {
    background: #f8fafc;
    border: 1px solid #e2e8f0;
    border-radius: 8px;
    padding: 16px;
    margin-bottom: 16px;
}

.section-title {
    font-size: 13px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 12px;
    padding-bottom: 8px;
    border-bottom: 2px solid #3b82f6;
}
```

### Circular Likert Ratings

```css
.likert-circle {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    border: 2px solid #e2e8f0;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

.likert-option input:checked + .likert-circle {
    background: #8b5cf6;
    color: white;
    border-color: #7c3aed;
}
```

## Combining with Instance Display

Custom layouts work alongside `instance_display` configuration. The instance content (images, text, dialogues) renders separately above your annotation forms.

```yaml
instance_display:
  fields:
    - key: image_url
      type: image
      display_options:
        zoomable: true

task_layout: layouts/custom_task_layout.html

annotation_schemes:
  - annotation_type: radio
    name: category
    labels: [A, B, C]
```

## Best Practices

1. **Match schema names**: Form `id` must exactly match `name` in `annotation_schemes`
2. **Sequential annotation IDs**: Use 0, 1, 2... for `data-annotation-id`
3. **Include required handlers**: Use `onclick="onlyOne(this);registerAnnotation(this);"` for radio, `onclick="registerAnnotation(this);"` for checkbox
4. **Test responsiveness**: Use media queries for mobile support
5. **Keep accessibility**: Use proper labels and maintain keyboard navigation

## Troubleshooting

### Annotations not saving

Check that:
- Form `id` matches annotation scheme `name`
- Inputs have `schema` and `label_name` attributes
- Click handlers (`registerAnnotation`) are present

### Styles not applying

- Ensure CSS specificity is high enough to override defaults
- Check that your `<style>` block is inside the layout file
- Use browser dev tools to inspect applied styles

### Layout not loading

- Verify path in `task_layout` is relative to config file
- Check for HTML syntax errors
- Review server logs for error messages

## Further Reading

- [Instance Display](/docs/core-concepts/instance-display) - Configure what content to show
- [UI Configuration](/docs/core-concepts/ui-configuration) - Interface customization options
- [Annotation Schemes](/docs/core-concepts/annotation-schemes) - Available annotation types

For implementation details, see the [source documentation](https://github.com/davidjurgens/potato/blob/main/docs/layout_customization.md).
