Problem
You've created a view, and would like each row of the view result to have an alternating class name, like even
and odd
. This is also referred to as 'zebra styles'.
Solution
Approach
Override the appropriate twig template file and add a bit of twig logic to make the alternating class names happen.
Spoiler alert: it will only take a single line of custom code.
Steps
- determine the appropriate template file to copy from
/core/modules/views/templates
- copy the file over to
/themes/custom/YOUR_THEME/templates/views
- rename the file, taking into account Drupal's Twig template naming conventions
- add your custom logic to the file
- clear your caches
Implementation
In this example:
- our view is an unformatted list of articles
- our view's identifier (machine name) is articles
Step 1: copy the right template file into your theme
Since the view's format is set to unformatted list, copy /core/modules/views/templates/views-view-unformatted.html.twig
to /themes/custom/YOUR_THEME/templates/views/
.
Drupal will always check your theme folder first for template files to use. If it doesn't find an appropriate template file, it will fall back on the default ones.
Step 2: rename your template file (if appropriate)
If you don't rename your copied template file at this point, any changes you make will apply to all of your site's views that use the unformatted_list format setting.
In you want this template to only apply to your articles view, rename the copied template to:
/themes/custom/YOUR_THEME/templates/views/templates/views-view-unformatted--articles.html.twig
→ See also: Drupal 8/9 Twig template naming conventions
Step 3: add your logic
Here's the default, unmodified Twig template file (comments removed):
→ /core/modules/views/templates/views-view-unformatted.html.twig
{% if title %}
<h3>{{ title }}</h3>
{% endif %}
{% for row in rows %}
{%
set row_classes = [
default_row_class ? 'views-row',
]
%}
<div{{ row.attributes.addClass(row_classes) }}>
{{- row.content -}}
</div>
{% endfor %}
In your copied tempate file, under default_row_class ? 'views-row',
add the following single line of code:
cycle(['even', 'odd'], loop.index0)
So the complete code becomes:
→ /themes/custom/YOUR_THEME/templates/views/templates/views-view-unformatted--articles.html.twig
{% if title %}
<h3>{{ title }}</h3>
{% endif %}
{% for row in rows %}
{%
set row_classes = [
default_row_class ? 'views-row',
cycle(['even', 'odd'], loop.index0),
]
%}
<div{{ row.attributes.addClass(row_classes) }}>
{{- row.content -}}
</div>
{% endfor %}
Explanation
-
cycle()
is a core twig function that cycles through a given array of values. -
loop.index0
indicates the position (index) of the iterator during the looping, starting at 0.
→ More info on twig functions: https://twig.sensiolabs.org/doc/2.x/functions/index.html.
Since this template file will be used each time a row of the articles view is rendered, either 'even' or 'odd' will be added to row_classes
, which holds the list of classes to be used in the <div>
that wraps around the row's { row.content }
.
Summary
Override the default views-view-unformatted.html.twig
template and add your logic:
- Copy
/core/modules/views/templates/views-view-unformatted.html.twig
into your theme. - Rename the template file so it applies only to your target view.
- Add a line of code that cycles between two given class names.
- Clear your caches.
Further resources
- Drupal 8/9 Twig template naming conventions
- https://twig.sensiolabs.org/doc/2.x/functions/index.html
If you liked this article, you'll love our courses on Drupal 8/9 Site Building, Module Development, and Theme Development.
Top comments (0)