Layout Customization Guide
This guide explains how to create sophisticated, custom visual layouts for your annotation tasks using custom CSS and HTML templates.
Overview
Potato provides two approaches for customizing the annotation interface layout:
- Auto-generated layouts: Potato generates a
layouts/task_layout.htmlfile that you can edit - Custom layout files: Create your own HTML template with full control over styling
Project-level Base CSS (base_css)
For global styling that applies across all pages (annotation, consent, instructions, etc.), use the base_css config option:
base_css: "styles/custom.css"
The CSS file is read at server startup and injected as a <style id="potato-project-base-css"> block in the <head> of every page. It loads after all built-in Potato styles, so your rules take precedence.
The path is resolved relative to the config file's directory. Absolute paths are also supported.
Example styles/custom.css:
body {
font-family: 'Georgia', serif;
background-color: #f5f5dc;
}
.navbar {
background-color: #336699 !important;
}
Note: Changes to the CSS file require a server restart. A missing file will log a warning rather than crash.
Quick Start
Using Auto-generated Layouts
- Run your server once - Potato creates
layouts/task_layout.html - Edit the generated file to customize styling
- Your changes persist across server restarts (unless you modify
annotation_schemesin the config)
Using Custom Layout Files
- Create your layout file (e.g.,
layouts/custom_task_layout.html) - Reference it in your config:
task_layout: layouts/custom_task_layout.html
Layout File Structure
A custom layout file must include:
<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:
id: Must match thenamein your config'sannotation_schemesclass: Includeannotation-formand the type (e.g.,radio,multiselect)data-annotation-id: Sequential index (0, 1, 2...)schemaattribute on fieldset and inputs
Required Input Attributes
<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 sophisticated example layouts demonstrating advanced customization:
1. Content Moderation Dashboard
Location: examples/custom-layouts/content-moderation/
Features: - Warning banner header with content metadata - 2-column grid for violation categories - Color-coded severity levels (green/yellow/red) - Professional moderation workflow
Run:
python potato/flask_server.py start examples/custom-layouts/content-moderation/config.yaml -p 8000
2. Customer Service Dialogue QA
Location: examples/custom-layouts/dialogue-qa/
Features: - Case header with metadata badges - Grouped assessment sections - Circular Likert-scale ratings - Quality issues checklist - Color-coded resolution indicators
Run:
python potato/flask_server.py start examples/custom-layouts/dialogue-qa/config.yaml -p 8000
3. Medical Image Review
Location: examples/custom-layouts/medical-review/
Features: - Professional medical UI styling - Two-column layout for location/severity - Grouped findings sections - Structured medical reporting workflow - Recommendation cards with descriptions
Run:
python potato/flask_server.py start examples/custom-layouts/medical-review/config.yaml -p 8000
CSS Techniques
Grid Layouts
Create multi-column layouts:
.annotation-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
}
/* Full-width items */
.full-width {
grid-column: 1 / -1;
}
/* Responsive */
@media (max-width: 768px) {
.annotation-grid {
grid-template-columns: 1fr;
}
}
Color-Coded Options
Style radio buttons with severity colors:
.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;
}
/* None - Green */
.severity-none .severity-label {
background: #dcfce7;
color: #166534;
}
.severity-none input:checked + .severity-label {
background: #22c55e;
color: white;
}
/* Severe - Red */
.severity-severe .severity-label {
background: #fee2e2;
color: #991b1b;
}
.severity-severe input:checked + .severity-label {
background: #ef4444;
color: white;
}
Section Styling
Create visual groupings:
.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;
}
/* Accent border */
.primary-section {
border-left: 4px solid #3b82f6;
}
Circular Likert Ratings
.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;
}
Header Banners
.warning-banner {
background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
border: 2px solid #f59e0b;
border-radius: 8px;
padding: 12px 20px;
display: flex;
align-items: center;
gap: 12px;
}
Combining with Instance Display
Custom layouts work alongside instance_display configuration. The instance content (images, text, dialogues) is rendered separately above your annotation forms.
# Instance display renders content
instance_display:
fields:
- key: image_url
type: image
display_options:
zoomable: true
# Custom layout controls annotation form presentation
task_layout: layouts/custom_task_layout.html
# Annotation schemes define the data structure
annotation_schemes:
- annotation_type: radio
name: category
# ...
Best Practices
- Match schema names: Form
idmust exactly matchnameinannotation_schemes - Sequential annotation IDs: Use 0, 1, 2... for
data-annotation-id - Include required handlers: Use
onclick="onlyOne(this);registerAnnotation(this);"for radio,onclick="registerAnnotation(this);"for checkbox - Test responsiveness: Use media queries for mobile support
- Keep accessibility: Use proper labels, maintain keyboard navigation
- Hide default styling: Override Potato's default form styles with your CSS
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_layoutis relative to config file - Check for HTML syntax errors
- Review server logs for error messages
Related Documentation
- Instance Display - Configure what content to show
- Annotation Schemas - Available annotation types
- Configuration Reference - Full configuration options