Record landing page
The record landing page displays detailed information about a single record. This page is rendered through a generic JinjaX component provided by oarepo-ui that can be customized via model-specific partial templates.
Architecture
The record detail page follows this flow:
- User accesses a record URL (e.g.,
/mymodels/<pid_value>) - UI Resource view (
record_detail) fetches the record from the service layer - Resource components prepare additional context data
- RecordDetail.jinja component renders the page using base template and model partials
RecordDetail.jinja Component
The default record detail component is provided by oarepo-ui (source ):
{#def
record,
record_ui,
files,
media_files,
permissions,
is_preview,
include_deleted,
is_draft,
model,
model_name,
community,
community_ui,
user_avatar,
record_owner_id,
ui_links,
extra_context,
d,
#}
{% extends "invenio_app_rdm/records/detail.html" %}
{%- block page_body %}
{%- block page_banners -%}
{% include model_name ~ "/record_detail/banners.html" %}
{%- endblock page_banners -%}
{%- block page_main -%}
{% include model_name ~ "/record_detail/main.html" %}
{%- endblock page_main -%}
{%- endblock page_body %}
{%- block javascript %}
{{ super() }}
{% if not embedded %}
{{ webpack["record_sharing.js"] }}
{% endif %}
{%- endblock javascript %}The embedded flag toggles certain UI features when the detail page is rendered within another context (e.g., inside a modal or iframe).
Component Props
The component receives these props from the UI resource:
| Prop | Description |
|---|---|
record | API record object with id, pid, links, metadata, access, files |
record_ui | Record metadata serialized for UI representation |
files | Record files entries |
media_files | System/media files entries |
permissions | User permissions to record (can_edit, can_update, can_manage) |
is_preview | Whether viewing in preview mode |
include_deleted | Whether to include deleted records |
is_draft | Whether record is a draft |
model | Record model configuration |
model_name | Name of the record model (e.g.: mymodel) |
community | Community metadata if record belongs to one |
community_ui | Community data serialized for UI representation |
user_avatar | URL of the current user’s avatar image |
record_owner_id | ID of the record owner user |
ui_links | UI navigation links |
extra_context | Additional context from resource components |
d | Shorthand for record.metadata |
Available Blocks
| Block | Purpose |
|---|---|
page_body | Main page wrapper - controls overall page structure |
page_banners | Banner region for notices, warnings, status messages |
page_main | Main content area - includes the model’s main.html partial |
javascript | JavaScript bundles |
UI Resource Configuration
The record detail route is defined in your model’s UI resource config:
from oarepo_ui.resources.records.config import RecordsUIResourceConfig
class MymodelUIResourceConfig(RecordsUIResourceConfig):
blueprint_name = "mymodel"
url_prefix = "/mymodel"
routes = {
"record_detail": "/records/<pid_value>",
# ... other routes
}See UI Resource Views for full details on UI resources.
Template Structure
The RecordDetail.jinja base page component includes model-specific partial templates. For a model named mymodel, it would include these template partials:
- banners.html
- main.html
record_detail/banners.html
The banners.html template (source ) is included via the page_banners block and displays contextual banners at the top of the detail page.
If you choose to extend from oarepo_ui/record_detail/banners.html, you get access to three overridable blocks: banner_community_header, banner_preview_header, and banner_version_header. Otherwise, you can put any content directly in your model-specific template.
Option 1: Extend Default Banners
Extend from the default banners template to override specific blocks:
{% extends "oarepo_ui/record_detail/banners.html" %}
{%- block banner_preview_header -%}
{{ super() }}
{%- if extra_context.custom_warning %}
<div class="ui message warning">
<i class="exclamation triangle icon"></i>
{{ extra_context.custom_warning }}
</div>
{%- endif %}
{%- endblock banner_preview_header -%}
{%- block banner_version_header -%}
{# Hide version warning #}
{%- endblock banner_version_header -%}
{%- block banner_community_header -%}
{# Hide community header #}
{%- endblock banner_community_header -%}Option 2: Custom Content
If you don’t extend the default banners, put any content directly in your template:
{# Custom banners without extending the default template #}
{%- if is_preview -%}
<div class="ui message info">
<i class="eye icon"></i>
You are viewing a preview. This record is not published yet.
</div>
{%- endif -%}
{%- if d.custom_field -%}
<div class="ui message warning">
<i class="warning icon"></i>
{{ d.custom_field }}
</div>
{%- endif -%}record_detail/main.html
The main.html template (source ) is included via the page_main block and renders the main content of the record detail page. It provides the following overridable blocks:
| Block | Purpose |
|---|---|
record_body | Main content wrapper (contains all other blocks) |
record_header | Header section |
record_header_button | Navigation header buttons (back to edit) |
record_header_info | Publication date, version, type, access status |
record_title | Record title and creators/contributors |
record_content | Main description section |
record_files | Files section with preview and list |
record_files_access_request | Access request form for restricted files |
record_media_files | System/media files section |
additional_record_details | Additional metadata from details.html |
record_footer | Footer section |
record_sidebar | Right sidebar from side_bar.html |
jump | ”Jump to top” button |
Use {{ super() }} within override blocks to preserve the parent template content. Omit {{ super() }} to completely replace the section. See Templating: Jinja for more on template inheritance.
Override Title and Add Content
{%- block record_title -%}
{{ super() }}
{# Add custom badge after title #}
<span class="ui label">MyModel</span>
{%- endblock record_title -%}
{%- block additional_record_details -%}
{{ super() }}
<div class="ui segment">
<h3>MyModel Metadata</h3>
<p>{{ d.custom_field }}</p>
</div>
{%- endblock additional_record_details -%}Hide Default Elements
{%- block record_header_info -%}
{# Hide publication date and version info #}
{%- endblock record_header_info -%}record_detail/side_bar.html
The sidebar template (source ) is included from invenio_app_rdm/records/details/side_bar.html. It composes the sidebar from multiple templates listed in the APP_RDM_DETAIL_SIDE_BAR_TEMPLATES configuration:
{%- for template_name in config.get("APP_RDM_DETAIL_SIDE_BAR_TEMPLATES", []) -%}
{% include template_name %}
{%- endfor -%}Adding Sidebar Widgets
To add custom sidebar widgets, add your template path to the configuration in your invenio.cfg:
APP_RDM_DETAIL_SIDE_BAR_TEMPLATES = [
"invenio_app_rdm/records/details/side_bar/versioning.html",
"invenio_app_rdm/records/details/side_bar/export_formats.html",
"invenio_app_rdm/records/details/side_bar/keywords.html",
"mymodel/records/detail/side_bar/custom_widget.html",
]Create your sidebar widget template:
<div class="ui segment">
<h3>Custom Widget</h3>
<p>Your custom sidebar content here.</p>
</div>Overriding the Entire Sidebar
If you need to completely replace the sidebar, override the record_sidebar block:
{%- block record_sidebar %}
{# Custom sidebar content - replaces default sidebar #}
<div class="ui segment">
<h3>Custom Sidebar</h3>
<p>Your custom content here.</p>
</div>
{%- endblock record_sidebar %}Using Resource Components
Add custom context data through resource components:
from oarepo_ui.resources.components import UIResourceComponent
class MymodelDetailComponent(UIResourceComponent):
def before_detail(self, resource, request, extra_context, **kwargs):
# Add custom data to template context
record = extra_context.get("record")
if record:
extra_context["related_records"] = self._get_related(record)
def _get_related(self, record):
# Fetch related records from service layer
return []Register in your UI resource config:
from .components import MymodelDetailComponent
class MymodelUIResourceConfig(RecordsUIResourceConfig):
components = [
MymodelDetailComponent,
]Access custom context in any override block:
{%- block additional_record_details -%}
{{ super() }}
{% if related_records %}
<div class="related-records">
<h3>Related Records</h3>
{% for rec in related_records %}
<div class="related-item">
<a href="{{ rec.links.self_html }}">{{ rec.metadata.title }}</a>
</div>
{% endfor %}
</div>
{% endif %}
{%- endblock additional_record_details -%}Replacing the Default Landing Page Template
By default, the record detail page uses the generic oarepo_ui.pages.RecordDetail template that includes your model-specific record_detail/banners.html and record_detail/main.html partials.
If you need to replace the entire landing page template with your own model-specific implementation:
Create a Custom Page Component
{#def record, record_ui, files, media_files, permissions, is_preview, include_deleted, is_draft, model_name, community, community_ui, user_avatar, record_owner_id, d, oai_record #}
{% extends "invenio_app_rdm/records/detail.html" %}
{# Your custom page structure here #}
{%- block page_body -%}
<div class="my-custom-landing-page">
{# Your custom content #}
<h1>{{ d.title }}</h1>
</div>
{%- endblock page_body -%}Register it in your UI resource config:
class MymodelUIResourceConfig(RecordsUIResourceConfig):
templates = {
"record_detail": "mymodel.pages.RecordDetail",
}