Post

Radix Templates

working with Radix theme Templates and components in Drupal

Radix promotes the use of self contained components. By using the radix cli, you can create your own components to override the radix components.

1
drupal-radix-cli add block

Then you can override the block using the block component in your radix theme.

1
2
3
4
5
6
7
8
9
10
{#
/**
 * @file
 * Template for a block.
 */
#}

{% include 'radix:block' with {
  label: false,
} %}

Whatever option you choose from the for coming list, all the necessary files will be copied into your themes component folder to create an overriding component. That being said, you can still override these templates in the manual way by getting the theme template suggested name of the template and override the radix template with the relative code samples below.

** Prerequisites **

twig debug installed

Heading

1
2
3
4
5
6
7
8
9
  {% if title %}
    {%
      include 'radix:heading' with {
        heading_html_tag: 'h3',
        content: title
      }
    %}
  {% endif %}

Refers to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
{#
/**
 * @file
 * Heading component.
 *
 * Bootstrap Documentation
 * https://getbootstrap.com/docs/5.3/content/typography/#headings
 *
 * Full List Utility Classes
 * https://github.com/twbs/bootstrap/blob/v5.3.0/dist/css/bootstrap.css#L214
 *
 * Available properties:
 * - heading_html_tag : The HTML tag to use for the header.
 * Defaults to h1 (h1|h2|h3|h4|h5|h6)
 * - display: When you need a heading to stand out, consider using a display heading—a larger,
 * slightly more opinionated heading style.
 * - content: Content text for the heading.
 * - heading_attributes: Attributes array.
 * - heading_utility_classes: This property contains an array of utility classes.
 * - heading_link_utility_classes: This property contains an array of utility classes.
 * - title_link: Optional link for the heading. If provided, it wraps the heading.
 */
#}
{% apply spaceless %}

{% set heading_html_tag = heading_html_tag|default('h2') %}
{% set display = [display] ?? [] %}
{% set heading_attributes = heading_attributes ?: create_attribute() %}
{% set heading_classes = display|merge(heading_utility_classes ?: []) %}

{% if title_link %}
  {% set heading_link_attributes = create_attribute().setAttribute('href', title_link) %}
  {% set heading_link_classes = heading_link_utility_classes ?: [] %}
{% endif %}

{% if content %}
  <{{heading_html_tag}} {{ heading_attributes.addClass(heading_classes) }}>
    {% block heading_content %}
      {% if title_link %}
        <a {{ heading_link_attributes.addClass(heading_link_classes) }}>
          {{ content }}
        </a>
      {% else %}
        {{ content }}
      {% endif %}
    {% endblock %}
  </{{heading_html_tag}}>
{% endif %}

{% endapply %}

Field

In twig debug you should see

BEGIN OUTPUT from 'themes/custom/theme_name/templates/field/field.html.twig' and in this file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{% include 'radix:field' with {
  label_hidden: false,
  multiple: true,
  label: 'Field Label',
  items: [
    { content: '<p>Item one content</p>' },
    { content: '<p>Item two content</p>' },
    { content: '<p>Item three content</p>' }
  ],
  entity_type: 'node',
  field_name: 'field_example',
  field_type: 'text_long',
  label_display: 'above',
  attributes: create_attribute(),
  title_attributes: create_attribute()
} %}

The code from field.twig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
{#
/**
 * @file
 * Template for a field component.
 *
 * To override output, copy the "field.html.twig" from the templates directory
 * to your theme's directory and customize it, just like customizing other
 * Drupal templates such as page.html.twig or node.html.twig.
 *
 * Instead of overriding the theming for all fields, you can also just override
 * theming for a subset of fields using
 * @link themeable Theme hook suggestions. @endlink For example,
 * here are some theme hook suggestions that can be used for a field_foo field
 * on an article node type:
 * - field--node--field-foo--article.html.twig
 * - field--node--field-foo.html.twig
 * - field--node--article.html.twig
 * - field--field-foo.html.twig
 * - field--text-with-summary.html.twig
 * - field.html.twig
 *
 * Available variables:
 * - attributes: HTML attributes for the containing element.
 * - label_hidden: Whether to show the field label or not.
 * - title_attributes: HTML attributes for the title.
 * - label: The label for the field.
 * - multiple: TRUE if a field can contain multiple items.
 * - items: List of all the field items. Each item contains:
 *   - attributes: List of HTML attributes for each item.
 *   - content: The field item's content.
 * - entity_type: The entity type to which the field belongs.
 * - field_name: The name of the field.
 * - field_type: The type of the field.
 * - label_display: The display settings for the label.
 * - field_utility_classes: Additional classes to be added to the field wrapper.
  * - field_title_utility_classes: Additional classes to be added to the field title wrapper.
 *
 *
 * @see template_preprocess_field()
 */
#}
{%
  set classes = [
    'field',
    'field--name-' ~ field_name|clean_class,
    'field--type-' ~ field_type|clean_class,
    'field--label-' ~ label_display,
  ]
%}
{%
  set title_classes = [
    'field__label',
    label_display == 'visually_hidden' ? 'visually-hidden',
  ]
%}

{% if label_hidden %}
{% if multiple %}
<div{{ attributes.addClass(classes, 'field__items') }}>
{% for item in items %}
<div{{ item.attributes.addClass('field__item') }}>{{ item.content }}</div>
{% endfor %}
</div>
{% else %}
{% for item in items %}
<div{{ attributes.addClass(classes, 'field__item') }}>{{ item.content }}</div>
{% endfor %}
{% endif %}
{% else %}
<div{{ attributes.addClass(classes) }}>
<div{{ title_attributes.addClass(title_classes) }}>{{ label }}</div>
{% if multiple %}
<div class='field__items'>
{% endif %}
{% for item in items %}
<div{{ item.attributes.addClass('field__item') }}>{{ item.content }}</div>
{% endfor %}
{% if multiple %}
</div>
{% endif %}

  </div>
{% endif %}

Copy the above code into your custom file using one of the suggestions provided by twig debug

1
2
3
4
5
6
{%
  include 'radix:breadcrumb' with {
    breadcrumb: breadcrumb,
  }
%}

refers to

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{#
/**
 * @file
 * Template for a Breadcrumb component.
 *
 * Available config:
 * - breadcrumb_utility_classes: An array of utility classes.
 */
#}
{% apply spaceless %}

{%
  set breadcrumb_classes = [
    'breadcrumb',
  ]|merge(breadcrumb_utility_classes ?: [])
%}
{% set breadcrumb_attributes = attributes ?: create_attribute() %}

{% block breadcrumb %}
  {% if breadcrumb %}
    <nav aria-label="breadcrumb">
      <ol {{ breadcrumb_attributes.addClass(breadcrumb_classes) }}>
        {% for item in breadcrumb %}
          <li class="breadcrumb-item {{ not item.url ? 'active' }}">
            {% if item.url %}
              <a href="{{ item.url }}">{{ item.text }}</a>
            {% else %}
              {{ item.text }}
            {% endif %}
          </li>
        {% endfor %}
      </ol>
    </nav>
  {% endif %}
{% endblock %}

{% endapply %}

Block

1
2
3
4
5
6
7
8
9
10
{#
/**
 * @file
 * Template for a block.
 */
#}
{% include 'radix:block' with {
  html_tag: 'div',
} %}

Referring to file in radix/src/components/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
{#
/**
 * @file
 * Template for a Block component.
 *
 * Available config:
 * - html_tag: The HTML tag for the block.
 * - utility_classes: An array of utility classes.
 */
#}
{% set classes = [
  'block',
  bundle ? 'block--' ~ bundle|clean_class,
  id ? 'block--' ~ id|replace({"_": "-"})|clean_class,
]|merge(utility_classes ? utility_classes : []) %}

{% if html_tag %}
  <{{ html_tag }}{{ attributes|without('id').addClass(classes) }}>
{% endif %}

  {{ title_prefix }}
  {% if label %}
    {% block label %}
      <h2{{ title_attributes }}>{{ label }}</h2>
    {% endblock %}
  {% endif %}
  {{ title_suffix }}

  {% block content %}
    {{ content }}
  {% endblock %}

{% if html_tag %}
  </{{ html_tag }}>
{% endif %}

Views

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{% include 'radix:views-view' with {
  title: 'View Title',
  header: view_header,
  footer: view_footer,
  rows: view_rows,
  empty: 'No data available',
  pager: view_pager,
  exposed: exposed_filters,
  feed_icons: feed_icons,
  more: more_link,
  attachment_before: attachment_before_content,
  attachment_after: attachment_after_content,
  css_name: 'banner',
  dom_id: 'unique-dom-id',
  view_view_utility_classes: ['bg-primary, p-5, d-flex, align-items-center']
} %}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
{#
/**
 * @file
 * Theme override for main view template.
 *
 * Available variables:
 * - attributes: Remaining HTML attributes for the element.
 * - css_name: A css-safe version of the view name.
 * - css_class: The user-specified classes names, if any.
 * - header: The optional header.
 * - footer: The optional footer.
 * - rows: The results of the view query, if any.
 * - empty: The content to display if there are no rows.
 * - pager: The optional pager next/prev links to display.
 * - exposed: Exposed widget form/info to display.
 * - feed_icons: Optional feed icons to display.
 * - more: An optional link to the next page of results.
 * - title: Title of the view, only used when displaying in the admin preview.
 * - title_prefix: Additional output populated by modules, intended to be
 *   displayed in front of the view title.
 * - title_suffix: Additional output populated by modules, intended to be
 *   displayed after the view title.
 * - attachment_before: An optional attachment view to be displayed before the
 *   view content.
 * - attachment_after: An optional attachment view to be displayed after the
 *   view content.
 * - dom_id: Unique id for every view being printed to give unique class for
 *   Javascript.
 *
 * @see template_preprocess_views_view()
 */
#}
{% apply spaceless %}

{% set views_attributes = attributes ?: create_attribute() %}
{% set views_title_attributes = views_title_attributes ?: create_attribute() %}
{% set views_header_attributes = views_header_attributes ?: create_attribute() %}
{% set views_filters_attributes = views_filters_attributes ?: create_attribute() %}
{% set views_rows_attributes = views_rows_attributes ?: create_attribute() %}
{% set views_empty_attributes = views_empty_attributes ?: create_attribute() %}
{% set views_footer_attributes = views_footer_attributes ?: create_attribute() %}
{% set views_attachment_before_attributes = views_attachment_before_attributes ?: create_attribute() %}
{% set views_attachment_after_attributes = views_attachment_after_attributes ?: create_attribute() %}
{% set views_pager_attributes = views_pager_attributes ?: create_attribute() %}
{% set views_more_attributes = views_more_attributes ?: create_attribute() %}
{% set views_feed_icons_attributes = views_feed_icons_attributes ?: create_attribute() %}

{%
  set views_classes = [
    'view',
    'view-' ~ id|clean_class,
    'view-id-' ~ id,
    'view-display-id-' ~ display_id,
    dom_id ? 'js-view-dom-id-' ~ dom_id,
    css_name ? 'view-' ~ css_name,
  ]|merge(view_view_utility_classes ?: [])
%}

{%
  set views_title_classes = [
    'view-title',
  ]|merge(views_title_utility_classes ?: [])
%}

{%
  set views_header_classes = [
    'view-header',
  ]|merge(views_header_utility_classes ?: [])
%}

{%
  set views_filters_classes = [
    'view-filters',
  ]|merge(views_filters_utility_classes ?: [])
 %}

{%
  set views_rows_classes = [
    'view-content',
  ]|merge(views_rows_utility_classes ?: [])
%}

{%
  set views_empty_classes = [
    'view-empty',
  ]|merge(views_empty_utility_classes ?: [])
%}

{%
  set views_footer_classes = [
    'view-footer',
  ]|merge(views_footer_utility_classes ?: [])
%}

{%
  set views_attachment_before_classes = [
    'attachment',
    'attachment-before',
  ]|merge(views_attachment_before_utility_classes ?: [])
%}

{%
  set views_attachment_after_classes = [
    'attachment',
    'attachment-after',
  ]|merge(views_attachment_after_utility_classes ?: [])
%}

{%
  set views_pager_classes = [
    'pager',
  ]|merge(views_pager_utility_classes ?: [])
%}

{%
  set views_more_classes = ['']|merge(views_more_utility_classes ?: [])
%}

{%
  set views_feed_icons_classes = [
    'feed-icons',
  ]|merge(views_feed_icons_utility_classes ?: [])
%}

<div {{ views_attributes.addClass(views_classes) }}>
  {% block views_view_wrapper %}
    {{ title_prefix }}
    {% block views_view_title %}
      {% if title %}
        <div {{ views_title_attributes.addClass(views_title_classes) }}>
          {{ title }}
        </div>
      {% endif %}
    {% endblock %}
    {{ title_suffix }}

    {% block views_header %}
      {% if header %}
        <div {{ views_header_attributes.addClass(views_header_classes) }}>
          {{ header }}
        </div>
      {% endif %}
    {% endblock %}

    {% block views_filters %}
      {% if exposed %}
        <div {{ views_filters_attributes.addClass(views_filters_classes) }}>
          {{ exposed }}
        </div>
      {% endif %}
    {% endblock %}

    {% block views_attachment_before %}
      {% if attachment_before %}
        <div {{ views_attachment_before_attributes.addClass(views_attachment_before_classes) }}>
          {{ attachment_before }}
        </div>
      {% endif %}
    {% endblock %}

    {% block views_rows %}
      {% if rows %}

        <div {{ views_rows_attributes.addClass(views_rows_classes) }}>
          {{ rows }}
        </div>
      {% elseif empty %}
        <div {{ views_empty_attributes.addClass(views_empty_classes) }}>
          {{ empty }}
        </div>
      {% endif %}
    {% endblock %}

    {% block views_pager %}
      {% if pager %}
        <div {{ views_pager_attributes.addClass(views_pager_classes) }}>
          {{ pager }}
        </div>
      {% endif %}
    {% endblock %}

    {% block views_attachment_after %}
      {% if attachment_after %}
        <div {{ views_attachment_after_attributes.addClass(views_attachment_after_classes) }}>
          {{ attachment_after }}
        </div>
      {% endif %}
    {% endblock %}

    {% block views_more %}
      {% if more %}
        {{ more|add_class(views_more_classes) }}
      {% endif %}
    {% endblock %}

    {% block views_footer %}
      {% if footer %}
        <div {{ views_footer_attributes.addClass(views_footer_classes) }}>
          {{ footer }}
        </div>
      {% endif %}
    {% endblock %}

    {% block views_feed_icons %}
      {% if feed_icons %}
        <div {{ views_feed_icons_attributes.addClass(views_feed_icons_classes) }}>
          {{ feed_icons }}
        </div>
      {% endif %}
    {% endblock %}
  {% endblock %}
</div>

{% endapply %}

unformatted views

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{%
  include 'radix:views-view--unformatted' with {
    title: 'View Title',
    rows: view_rows,
    row_utility_classes: [
      'col-12',
      'col-md-6',
      'col-lg-4',
    ],
    default_row_class: true,
    rows: rows|map(row => row|merge({
      attributes: row.attributes.setAttribute('data-row-color', 'purple')
    })),
  }
%}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{#
/**
 * @file
 * Implements a template to display a view of unformatted rows.
 *
 * Available variables:
 * - title: The title of this group of rows. Can be empty.
 * - rows: An array of the view's row items. Each row contains:
 *   - attributes: The HTML attributes for the row.
 *   - content: The actual content of the row.
 * - view: The view object.
 * - default_row_class: A boolean indicating whether default row classes should be used.
 * - row_utility_classes: An array of optional utility classes to be used.
 *
 * @see template_preprocess_views_view_unformatted()
 */
#}
{% apply spaceless %}

{% block views_unformatted_title %}
  {% if title %}
    {%
      include 'radix:heading' with {
        heading_html_tag: 'h3',
        content: title
      }
    %}
  {% endif %}
{% endblock %}

{% block views_unformatted_rows %}
  {% for row in rows %}
    {%
      set row_classes = [
        default_row_class ? 'views-row',
      ]|merge(row_utility_classes ?: [])
    %}

    <div{{row.attributes.addClass(row_classes)}}>
      {{ rows }}
    </div>
  {% endfor %}
{% endblock %}

{% endapply %}

Overide node

In twig debug BEGIN OUTPUT from 'themes/custom/radix_blocks/templates/content/node.html.twig'

In node.html.twig

1
{% extends "@radix/content/node.twig" %}

The code from this file which is located in themes/radix/src/components/content/node.twig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
{#
/**
 * @file
 * Template for a Node.
 */
#}
{%
  set classes = [
  'node',
  node.isPromoted() ? 'node--promoted',
  node.isSticky() ? 'node--sticky',
  not node.isPublished() ? 'node--unpublished',
  node.bundle|clean_class,
  node.bundle|clean_class ~ '--' ~ view_mode|clean_class,
]
%}
<article{{ attributes.addClass(classes) }}>
  {{ title_prefix }}
  {{ title_suffix }}

  {% block content %}
    {% if not page %}
      <h2{{ title_attributes }}>
        <a href="{{ url }}" rel="bookmark">{{ label }}</a>
      </h2>
    {% endif %}

    {% if display_submitted %}
      <footer>
        {{ author_picture }}
        <div{{ author_attributes }}>
          {% trans %}Submitted by {{ author_name }} on {{ date }}{% endtrans %}
          {{ metadata }}
        </div>
      </footer>
    {% endif %}

    <div{{ content_attributes }}>
      {{ content }}
    </div>
  {% endblock %}
</article>

Overide a paragraphs module

overide paragraphs module

Overide node title

BEGIN OUTPUT from 'core/modules/node/templates/field--node--title.html.twig'

Code from field–node–title.html.twig file

1
2
3
4
5
6
7
8
9
{% if not is_inline %}
  {% include "field.html.twig" %}
{% else %}
<span{{ attributes }}>
  {%- for item in items -%}
    {{ item.content }}
  {%- endfor -%}
</span>
{% endif %}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
{#
/**
 * @file
 * Template for Navbar component.
 *
 * Available config:
 * - navbar_container_type: false | sm | md | lg | xl | xxl | fluid
 * - placement: default | fixed-top | fixed-bottom | sticky-top
 * - navbar_expand: sm | md | lg | xl | false
 * - navbar_theme: dark | light (default: light)
 * - navbar_utility_classes: An array of utility classes.
 *
 * Available blocks:
 * - branding
 * - left
 * - right
 */
#}
{% apply spaceless %}

{% set nav_attributes = nav_attributes ?: create_attribute() %}
{% set navbar_container_attributes = navbar_container_attributes ?: create_attribute() %}

{% set placement = placement ?? '' %}
{% set navbar_expand = navbar_expand ?? 'lg' %}
{% set navbar_theme = navbar_theme ?? null %}

{%
  set navbar_container_classes = [
    navbar_container_type is null ? 'container' : '',
    navbar_container_type ? 'container' ~ (navbar_container_type ? '-' ~ navbar_container_type : '') : '',
  ]|merge(navbar_container_utility_classes ?: [])
%}

{%
  set nav_classes = [
    'navbar',
    navbar_expand ? 'navbar-expand-' ~ navbar_expand : '',
    placement,
  ]|merge(navbar_utility_classes ?: [])
%}

{% if navbar_theme %}
  {% set nav_attributes = nav_attributes.setAttribute('data-bs-theme', navbar_theme) %}
{% endif %}

<nav {{ nav_attributes.addClass(nav_classes) }}>
  <div {{ navbar_container_attributes.addClass(navbar_container_classes) }}>
    {% block branding %}
      {{ branding }}
    {% endblock %}

    {% block navbar_toggler %}
      <button class="navbar-toggler collapsed" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbar-collapse" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
    {% endblock %}

    <div class="collapse navbar-collapse">
      {% block left %}
        {{ left }}
      {% endblock %}

      {% block right %}
        {{ right }}
      {% endblock %}
    </div>
  </div>
</nav>

{% endapply %}

This post is licensed under CC BY 4.0 by the author.