UI Components Reference¶
Complete reference for Django Cotton UI components used in SATHI.
Overview¶
SATHI uses Django Cotton for reusable, maintainable UI components. All components follow consistent design patterns and support Tailwind CSS styling.
Key Benefits:
Consistent UI across the application
Reduced code duplication
Easier maintenance and updates
Built-in accessibility features
Mobile-responsive by default
Card Components¶
Card Component¶
Flexible container for structured content.
Basic Usage:
{% load cotton %}
<c-card title="Patient Information">
<p>Card content goes here...</p>
</c-card>
Props:
Prop |
Type |
Default |
Description |
|---|---|---|---|
|
string |
Card title/header text |
|
|
string |
Optional subtitle below title |
|
|
string |
HTML for header action buttons |
|
|
string |
HTML content for footer |
|
|
string |
“md” |
Shadow level: none, sm, md, lg, xl |
|
string |
“md” |
Border radius: none, sm, md, lg, xl |
|
string |
“light” |
Border style: none, light, medium, strong |
|
string |
“md” |
Padding level: none, sm, md, lg, xl |
|
string |
“bg-gray-50” |
Header background color |
|
string |
“bg-white” |
Body background color |
|
string |
“bg-gray-50” |
Footer background color |
Advanced Examples:
<!-- Card with header actions -->
<c-card
title="Diagnoses"
header_actions='<button class="btn btn-primary">Add New</button>'>
<p>Diagnoses list...</p>
</c-card>
<!-- Card with footer -->
<c-card
title="Patient Details"
footer='<div class="text-right"><button>Save</button></div>'>
<p>Form fields...</p>
</c-card>
<!-- Custom styling -->
<c-card
title="Important Notice"
shadow="lg"
rounded="xl"
border="strong"
header_bg="bg-red-50"
body_bg="bg-red-100">
<p>Critical information...</p>
</c-card>
Mobile Responsiveness:
<!-- Responsive content inside cards -->
<c-card title="Patient Info" padding="md">
<div class="flex flex-col sm:flex-row sm:justify-between gap-3">
<div class="flex-1 min-w-0">
<h3 class="truncate">{{ patient.name }}</h3>
<p class="text-sm text-gray-600">{{ patient.id }}</p>
</div>
<div class="flex space-x-2 sm:flex-shrink-0">
<!-- Action buttons -->
</div>
</div>
</c-card>
Field Display Component¶
Display label-value pairs with optional badge styling.
Usage:
<c-field_display
label="Patient Name"
value="{{ patient.name }}" />
<!-- With badge -->
<c-field_display
label="Status"
value="Active"
badge="true"
badge_color="green" />
Props:
label- Field label textvalue- Field value to displaybadge- Display as badge (true/false)badge_color- Badge color: blue, green, red, yellow, gray
Dropdown Components¶
Important Syntax Note¶
When passing dynamic values to Django Cotton components, use the : prefix:
:options="variable_name"instead ofoptions=variable_name:selected="request.GET.field"instead ofselected=request.GET.field:errors="form.field.errors"instead oferrors=form.field.errors
Static strings can be passed without the : prefix.
Filter Dropdown¶
For search/filter forms with HTMX integration.
Props:
name- Select element name (required)label- Label text (required)placeholder- Default option textoptions- List of options (required)selected- Currently selected valuerequired- Booleanhelp_text- Help text below dropdownhx_get- HTMX get URLhx_target- HTMX target elementhx_trigger- HTMX trigger event (default: “change”)
Examples:
<!-- Basic filter dropdown -->
<c-filter_dropdown
name="institution"
label="Institution"
placeholder="All Institutions"
:options="institutions"
:selected="request.GET.institution" />
<!-- With HTMX integration -->
<c-filter_dropdown
name="gender"
label="Gender"
placeholder="All Genders"
:options="gender_choices"
:selected="request.GET.gender"
hx_get="{% url 'patient_list' %}"
hx_target="#patientsTable" />
<!-- With help text -->
<c-filter_dropdown
name="diagnosis"
label="Diagnosis"
placeholder="All Diagnoses"
:options="diagnoses"
:selected="request.GET.diagnosis"
help_text="Select a diagnosis to filter patients" />
Option Formats:
Objects with id/name attributes:
institutions = [ {'id': 1, 'name': 'Hospital A'}, {'id': 2, 'name': 'Hospital B'} ]
Tuples (value, label):
gender_choices = [ ('M', 'Male'), ('F', 'Female') ]
Simple strings:
diagnoses = ['Cancer', 'Diabetes', 'Heart Disease']
Form Dropdown¶
For Django form fields with validation support.
Additional Props:
errors- Form field errors to displaycreate_link- URL for creating new optionscreate_text- Text for create link (default: “Create new option”)create_link_target- Target for create link
Examples:
<!-- Basic form dropdown -->
<c-form_dropdown
name="construct_scale"
label="Construct Scale"
placeholder="---------"
:options="form.construct_scale.field.queryset"
:selected="form.construct_scale.value"
:errors="form.construct_scale.errors"
required=true />
<!-- With create link -->
<c-form_dropdown
name="likert_response"
label="Likert Scale"
:options="likert_scales"
:selected="form.likert_response.value"
:errors="form.likert_response.errors"
create_link="{% url 'likert_scale_create' %}"
create_text="Create new Likert scale"
create_link_target="_blank" />
Language Selector¶
For navbar language switching.
Usage:
<c-language_selector />
Automatically displays available languages from Django settings.
List Card Component¶
Display items in a card-based list layout.
Usage:
<c-list_card
items="{{ patients }}"
title_field="name"
subtitle_field="patient_id"
url_field="get_absolute_url" />
Props:
items- List of items to displaytitle_field- Field name for titlesubtitle_field- Field name for subtitleurl_field- Field name for detail URLbadge_field- Field name for badge textbadge_color- Badge color
Paginator Component¶
Responsive pagination for Django ListView.
Basic Usage:
<c-paginator
:page_obj="page_obj"
:is_paginated="is_paginated" />
Props:
page_obj- Django Page object (required)is_paginated- Boolean (required)show_info- Show result count (default: true)show_page_numbers- Show page numbers (default: true)preserve_params- Preserve URL parameters (default: true)class- Additional CSS classes
Features:
Responsive: Mobile shows Previous/Next only, desktop shows full pagination
Accessible: ARIA labels and keyboard navigation
HTMX Integration: Built-in support for partial page updates
URL Preservation: Maintains search and filter parameters
Examples:
<!-- Full pagination -->
<c-paginator
:page_obj="page_obj"
:is_paginated="is_paginated"
show_info="true"
show_page_numbers="true"
class="my-8" />
<!-- Minimal pagination (mobile-friendly) -->
<c-paginator
:page_obj="page_obj"
:is_paginated="is_paginated"
show_info="false"
show_page_numbers="false" />
Django View Setup:
from django.views.generic import ListView
class PatientListView(ListView):
model = Patient
template_name = 'patientapp/patient_list.html'
context_object_name = 'patients'
paginate_by = 10 # Items per page
Template Integration:
{% extends 'base.html' %}
{% load cotton %}
{% block content %}
<div class="container mx-auto px-4">
{% for patient in patients %}
<!-- Patient cards -->
{% endfor %}
<c-paginator
:page_obj="page_obj"
:is_paginated="is_paginated" />
</div>
{% endblock %}
Best Practices¶
Component Usage¶
DO:
Use
:prefix for dynamic valuesProvide required props
Use semantic HTML inside components
Test on mobile devices
Include ARIA labels for accessibility
DON’T:
Mix static and dynamic syntax
Nest components unnecessarily
Override component styles directly
Forget error handling in forms
Responsive Design¶
<!-- Good: Mobile-first responsive layout -->
<c-card title="Details">
<div class="space-y-4 sm:space-y-0 sm:grid sm:grid-cols-2 sm:gap-6">
<c-field_display label="Name" value="{{ patient.name }}" />
<c-field_display label="ID" value="{{ patient.id }}" />
</div>
</c-card>
<!-- Good: Responsive button group -->
<div class="flex flex-col sm:flex-row gap-2">
<c-button full_width="true">Save</c-button>
<c-button variant="secondary" full_width="true">Cancel</c-button>
</div>
Accessibility¶
<!-- Good: Proper ARIA labels -->
<c-icon_button
icon="..."
aria_label="Edit patient details"
title="Edit" />
<!-- Good: Form validation -->
<c-form_dropdown
name="diagnosis"
label="Diagnosis"
:errors="form.diagnosis.errors"
required=true />
Performance¶
Use lazy loading for large lists
Implement HTMX for partial updates
Minimize nested components
Cache component renders when possible