Skip to Content
CustomizeModel UIRecord landing page

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:

  1. User accesses a record URL (e.g., /mymodels/<pid_value>)
  2. UI Resource view (record_detail) fetches the record from the service layer
  3. Resource components prepare additional context data
  4. 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 ):

oarepo_ui/templates/oarepo_ui/pages/RecordDetail.jinja
{#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:

PropDescription
recordAPI record object with id, pid, links, metadata, access, files
record_uiRecord metadata serialized for UI representation
filesRecord files entries
media_filesSystem/media files entries
permissionsUser permissions to record (can_edit, can_update, can_manage)
is_previewWhether viewing in preview mode
include_deletedWhether to include deleted records
is_draftWhether record is a draft
modelRecord model configuration
model_nameName of the record model (e.g.: mymodel)
communityCommunity metadata if record belongs to one
community_uiCommunity data serialized for UI representation
user_avatarURL of the current user’s avatar image
record_owner_idID of the record owner user
ui_linksUI navigation links
extra_contextAdditional context from resource components
dShorthand for record.metadata

Available Blocks

BlockPurpose
page_bodyMain page wrapper - controls overall page structure
page_bannersBanner region for notices, warnings, status messages
page_mainMain content area - includes the model’s main.html partial
javascriptJavaScript bundles

UI Resource Configuration

The record detail route is defined in your model’s UI resource config:

ui/mymodel/__init__.py
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:

ui/mymodel/templates/semantic-ui/mymodel/record_detail/banners.html
{% 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:

ui/mymodel/templates/semantic-ui/mymodel/record_detail/banners.html
{# 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:

BlockPurpose
record_bodyMain content wrapper (contains all other blocks)
record_headerHeader section
record_header_buttonNavigation header buttons (back to edit)
record_header_infoPublication date, version, type, access status
record_titleRecord title and creators/contributors
record_contentMain description section
record_filesFiles section with preview and list
record_files_access_requestAccess request form for restricted files
record_media_filesSystem/media files section
additional_record_detailsAdditional metadata from details.html
record_footerFooter section
record_sidebarRight 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

ui/mymodel/templates/semantic-ui/mymodel/record_detail/main.html
{%- 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

ui/mymodel/templates/semantic-ui/mymodel/record_detail/main.html
{%- 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:

side_bar.html
{%- 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:

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:

ui/mymodel/templates/semantic-ui/mymodel/records/detail/side_bar/custom_widget.html
<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:

ui/mymodel/templates/semantic-ui/mymodel/record_detail/main.html
{%- 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:

ui/mymodel/components.py
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:

ui/mymodel/__init__.py
from .components import MymodelDetailComponent class MymodelUIResourceConfig(RecordsUIResourceConfig): components = [ MymodelDetailComponent, ]

Access custom context in any override block:

ui/mymodel/templates/semantic-ui/mymodel/record_detail/main.html
{%- 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

ui/mymodel/templates/semantic-ui/mymodel/pages/RecordDetail.jinja
{#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:

ui/mymodel/__init__.py
class MymodelUIResourceConfig(RecordsUIResourceConfig): templates = { "record_detail": "mymodel.pages.RecordDetail", }
Last updated on