Jinja Macros
What are macros?
Jinja2 macros are reusable template components — think of them as functions that return HTML. Orchid has a large macro library covering modals, file uploaders, date pickers, cards, page headers, and more. Before writing raw HTML for a UI pattern, check the macros first.
Macro files
| File | Contents |
|---|---|
templates/macros.html | Core macros — modals, uploaders, date pickers, page headers, cards, etc. |
templates/macros_admin_sections.html | Admin section layout components |
templates/macros_profiles.html | Profile display macros (all four profile types) |
templates/macros_form_questions.html | Form question rendering (all question types) |
templates/case_management_macros.html | Case management UI components |
templates/contact_macros.html | Contact display macros |
templates/journey_cycle_macros.html | Medical cycle event display |
templates/user/macros.html | User portal macros |
templates/email_inbox/macros.html | Email inbox components |
How to use macros
Import and call
{# Import a single macro #}{% from 'macros.html' import modal, page_header %}
{# Or import all under an alias #}{% import 'macros.html' as m %}
{# Call it #}{{ page_header(title='My Page', breadcrumb=[('Home', '/'), ('My Page', None)]) }}Module-scoped macros
{% import 'user/macros.html' as user_macros %}{{ user_macros.profile_card(user) }}Commonly used macros from macros.html
Page headers
{% from 'macros.html' import page_header %}
{{ page_header( title='Case Overview', subtitle='John & Jane Doe', breadcrumb=[ ('Cases', url_for('admin_views.cases')), ('Case Overview', None) ]) }}Modals
{% from 'macros.html' import modal %}
{# Trigger button #}<button data-modal="my-modal">Open Modal</button>
{# Modal definition #}{{ modal( modal_id='my-modal', title='Confirm Action', body='Are you sure you want to do this?', confirm_text='Yes, do it', confirm_action='myJsFunction()') }}File uploaders
{% from 'macros.html' import file_uploader %}
{{ file_uploader( upload_url='/api/admin/case/document/upload', case_id=case.id, doc_type='general', label='Upload Document') }}Cards
{% from 'macros.html' import card %}
{{ card(title='Case Details', collapsible=True) }} {# card body content here #}{% endcall %}Date pickers
{% from 'macros.html' import date_picker %}
{{ date_picker( name='transfer_date', label='Transfer Date', value=transfer.transfer_date, required=True) }}Form question rendering
The macros_form_questions.html macro file renders all form question types:
{% from 'macros_form_questions.html' import render_question %}
{% for question in form.questions %} {{ render_question(question, answer=answers.get(question.id)) }}{% endfor %}This handles text inputs, textareas, multiple choice, checkboxes, date pickers, and file uploads automatically based on question.question_type.
Profile macros
{% from 'macros_profiles.html' import ed_profile_section, gc_profile_section %}
{# Render a specific ED profile section #}{{ ed_profile_section(profile, section='personal_info') }}Adding a new macro
When adding a new reusable UI component:
- Decide which macro file it belongs in (feature-specific → feature’s macros file; general-purpose →
macros.html) - Write the macro with clear parameter names and defaults:
{% macro my_new_component(title, items=[], show_count=True) %}<div class="my-component"> <h3>{{ title }}{% if show_count %} ({{ items|length }}){% endif %}</h3> {% for item in items %} <div class="item">{{ item.name }}</div> {% endfor %}</div>{% endmacro %}- Document the parameters with a comment above the macro
- Add it to this page under the relevant section