Skip to main content

Drupal 8/9/10: Adding Alternating Class Names to Views Rows with Twig

How to give each row in a Drupal view an alternating class name using a single line of code

Picture of a crosswalk.

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.

Approach

Override the appropriate twig template file and add a bit of twig logic to make the alternating class names happen:

  • 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

Example

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/views-view-unformatted--articles.html.twig

→ See also: Drupal 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),

Full code

→ /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 loops 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.