Using isotope gallery in drupal 8 views

Using isotope gallery in drupal 8 views

Profile picture for user alberto
Dimostrazione libreria isotope

At the time of writing the fancy module Isotope is not fully ported to drupal8. Waiting for a stable release for the new version of drupal, we can still build an isotope gallery with little customization in our theme.

Isotope by metafizzy is the well known javascript library that let you sort and filter content in a fancy and user-friendly way, improving user experience and giving some vivacity to our site.

So, let’s see it in action.


First step: integrating libraries to our theme.

First of all we have to include the isotope gallery we previously downloaded at metafizzy official website or github. If you don’t have one, create a new “js” folder in your theme and an “isotope” folder inside it, where we can put the downloaded isotope.pkgd.min.js file.
At the same time we will create a “custom” folder where we will put our custom javascript code (let’s call it “start-isotope.js) that will initialize the isotope function. The folder structure will look like:


Now we need to include these libraries in our theme, editing the libraries.yml file of our theme (usually theme_name.libraries.yml):

  version: 3.0.6
    js/isotope/isotope.pkgd.min.js: {}
    - core/jquery

  version: VERSION
    js/custom/start-isotope.js: {}
- core/jquery

Note that you may need to adjust the isotope version number with the actual version you downloaded. We also need to “inform” drupal that we will load these libraries, so we'll add some lines of code to our info.yml theme file (, at the libraries section if we have one:

  - my_theme/custom
  - my_theme/isotope

Finally we will edit the .theme file (my_theme.theme) to attach the libraries to the view that we'll create in the next step:

function my_theme_preprocess_views_view__my_isotope_list (&$variables) {
$variables['#attached']['library'][] = 'my_theme/isotope'; 
$variables['#attached']['library'][] = 'my_theme/custom'; 

If you are familiar with drupal name convention, you have noticed I’ve used the view list template, because I found much easier to control both the isotope elements and filters by an HTML list. You can find more on Drupal API documentation.

Second step: building the view.

This was a little tricky, because I would like to be as much close as possible to the Isotope module’s way. Assume we already have some content tagged with some terms. Let’s create a new “My Isotope” page view, showing content of some type, tagged with terms from our vocabulary we will use as filters, set the HTML list format of fields.
Usually we would like to show all elements, but if you have a large number of elements, you may use pagination to not affect speed load.

Under “Format > Format: settings” we can include the row class(es) for the isotope elements. In this case I will suggest something like: “ isotope-item {{ field_term }} ”. You may add your custom classes or the bootstrap columns classes (if you use a bootstrap based theme) to present the elements in a more clean display.

What make difference here is the class that identify the element (isotope-item) and the token {{ field_term }}, that represent the field term ID used in the node. Note that you need to add this field in the fields settings to use it as replacement.

Under "Wrapper Class" that contain the element add something like: “ myIsotopeContainer ”.
Add all the fields you need to show, let’s say:

  • a link to the content (you may want to output just the link text);
  • an image field (in most cases you may want to show an image, but it’s not mandatory, it could be a body or something else);
  • a title (not much to say about it);
  • the taxonomy term field, formatted as Entity ID which we will use as isotope filter.

Hide all of them to make things simple (and we want to make things simple, right?).

In the taxonomy term field, we will also rewrite the result with something like “ tid-{{ field_term }} ”. Be careful about formatting the taxonomy term as Entity ID if you use this rewriting result, if you don’t, be sure to use some delta value to return the term ID as result. This is the most clean way I found to output classes that matches filters. Other ways are possible, but they may result in confusion if you have terms composed by two words, blank spaces and so.
Finally we will add a Global custom text field (the simple thing I was talking about) and fill it with the hidden content wrapped in a single div:

<div><h2><a href="{{ view_node }}">{{ title }}</a></h2>{{ field_image }}</div>

Anything here is up to you: you may add classes, overlay animations and so on... it’s just an example.

Now add a View Attachment, which we will use to show filters. If you are not familiar with drupal View module, be careful to apply all next changes to the View Attachment itself (mean "Overwrite this attachment" select option), otherwise changes will apply to all views.

This attachment is an HTML list like before. This time, in the Settings option under Format, we will leave blank the Row Class field, while we will add a Wrapper Class (for example “ myIsotopeFilter ”) and a Class in the List (for example “ filter ”).

Under Fields we will add our taxonomy term field from the node, this time shown as label, but we don't want it to be linked to the entity (uncheck the relative box). Then we will add a (Content) ID field and hide it from display: this is important for aggregation that we will use later and which make me lost some hours to make it work properly. The taxonomy term field output should be rewritten to include the attribute:

data-filter=".tid-{{ field_term__target_id }}"

or the filters won't have an object to target (thanks Dwight!).

In the Sorting Criteria section add again “Content ID” field. I didn’t try a multiple filters isotope gallery, so I don’t know the exact behavior of the view in that case, but this should be the only sort filter you would have for the View attachment.

To reduce duplicates results you have to go under “Advanced” tab of the view and enable aggregation by clicking on “Use aggregation” and flagging the checkbox. Go back to Fields section, near to the “COUNT (Content ID)” field, click on Aggregation settings and select “Count”. Do the same thing under the Sorting Criteria: select “Count” for the aggregation settings. Save the view.

We are close to our goal, but there is still something missing. To be sure that our libraries will be loaded in the view page we need to add them in the view template.
Let's create a views-view--my_istope-list.html.twig template. There are several ways to override a view template, well documented in the Drupal API documentation I mentioned before. Maybe the best way is to copy the core view file you need and that you may find in the core/modules/views/templates folder. If you're using the HTML list like in this tutorial, you will copy the views-view-list.html.twig file in your theme templates folder (/themes/contrib/my_theme/templates) and rename it with the name of the view, like views-view--my_istope-list.html.twig. At the beginning of the twig file add

{{ attach_library(‘my_theme/isotope’) }}
{{ attach_library(‘my_theme/start-isotope’) }}

So the complete template file will look like:

 * @file
 * Default theme implementation for a view template to display a list of rows.
 * Available variables:
 * - attributes: HTML attributes for the container.
 * - rows: A list of rows for this list.
 *   - attributes: The row's HTML attributes.
 *   - content: The row's contents.
 * - title: The title of this group of rows. May be empty.
 * - list: @todo.
 *   - type: Starting tag will be either a ul or ol.
 *   - attributes: HTML attributes for the list element.
 * @see template_preprocess_views_view_list()
 * @ingroup themeable
{{ attach_library(‘my_theme/isotope’) }}
{{ attach_library(‘my_theme/start-isotope’) }}

{% if attributes -%}
  <div{{ attributes }}>
{% endif %}
  {% if title %}
    <h3>{{ title }}</h3>
  {% endif %}

  <{{ list.type }}{{ list.attributes }}>

    {% for row in rows %}
      <li{{ row.attributes }}>{{ row.content }}</li>
    {% endfor %}

  <{{ list.type }}>

{% if attributes -%}
{% endif %}

Third Step: initialize the isotope library with custom javascript.

This part depends on your needs and there are several ways to achieve your goal. To remain in the purpose of this tutorial edit the start-isotope.js file we created before and put a code like this:

     var masonryContainer = $(".myIsotopeContainer"),
  filtersMasonry = $(".myIsotopeFilter .filter");
  filtersMasonry.prepend( "<li class=\"active\"><a class=\"button\" href=\"#\" data-filter=\"*\"> All </a></li>" );
        itemSelector: '.isotope-item',
        layoutMode: 'fitRows',
    $('ul.filter a').click(function(){
      $("ul.filter a").removeClass("active");

      var selector = $(this).attr('data-filter');
             filter: selector,
             animationOptions: {
                 duration: 750,
                 easing: 'linear',
                 queue: false,
       return false;



Flush all caches in order to make drupal known of all theme’s changes and you’re done!

To view this demo in action, you can visit my portfolio page.

Please, feel free to comment and improve this guide if you want.


Inviato da Timmy (non verificato) Dom, 01/07/2018 - 20:50

This part starting "Now add a View Attachment..." up to the twig template is very hazy. Could you make it clearer? There is no "Number" option for aggregation and the description if fields is unclear at this stage.

Profile picture for user alberto
Inviato da alberto Lun, 02/07/2018 - 11:58

In risposta a di Timmy (non verificato)

Hi Timmy, and thank you for posting.

I'm sorry if it was unclear, English is not my native language, but I would like to share this solution since it would be useful to everyone.

I edited the part you mentioned, both on the "View attachment" part and the "twig template" part. I hope it's much clear now.

You are right about the "Number" option, It's the "Count" option, which is translated as "Numero" (means Number) in Italian. I worked on an italian installation of drupal, so it was my fault wrongly re-translating that option ;-)

Inviato da Joost (non verificato) Sab, 15/12/2018 - 21:39

Does this also work of you don’t display al you result on onze page? For example when you use pagers on your results.

Consenso Privacy
Profile picture for user alberto
Inviato da alberto Sab, 22/12/2018 - 11:21

In risposta a di Joost (non verificato)

Hi Joost, sorry for the late of my reply, but I had very busy days...

As mentioned in the article I didn't test it with pagers. I know it's possibile to use Isotope gallery and pagers, but I didn't implemented it on drupal and views.

If this is urgent to you, you would like to try and post back here for further documentation (seems this article is useful to lot of people).

If you can be patient, I may give it a try and let you know on here and sending you an e-mail. I also find that something missing in the tutorial and I need to review this article for better information.

Thank you!


Consenso Privacy
Inviato da Adam Smercis (non verificato) Lun, 14/01/2019 - 02:05

On your Example page, how did you add the "Tutti" i.e. "All" filter? Did you do it the 'hackish' way by adding a term "Tutti" to the vocabulary and by attaching this term to each and every entity? I hope, there's a cleaner possibility …

Consenso Privacy
Profile picture for user alberto
Inviato da alberto Lun, 14/01/2019 - 02:31

In risposta a di Adam Smercis (non verificato)

Hello Adam, it is a hackish way, but not done in taxonomy terms. If you look at the custom javascript file, you can see that the word "All" is hardcoded in the jquery.

I tried to make it translatable, unfortunately without success. Maybe not the best, but this is always cleaner then adding a taxonomy term "All" and manage its children...

Remember that this tutorial is just an easy workaround, more effort will be needed to make the isotope module ready for drupal8. When a beta release of isotope drupal module will be ready, I will recommend to use it instead!

Thank you for commenting, feel free to ask if you need help or post back better ideas. As told in a previous reply, I realized that the article need some adjustment ;)

Consenso Privacy
Inviato da Dwight Odelius (non verificato) Lun, 13/05/2019 - 20:42

Thank you so much for putting this together -- you saved me many hours.

There is a missing step here:

"Under Fields we will add our taxonomy term field from the node, this time shown as label, but we don't want it to be linked to the entity (uncheck the relative box). Then we will add a (Content) ID field..."

The taxonomy term field needs to be rewritten as something like:
{{ field_term }}
or the filters won't have an object to target. Your example page helped me figure this out, so thank you for including that.

Consenso Privacy
Inviato da Dwight Odelius (non verificato) Mar, 14/05/2019 - 13:47

In risposta a di Dwight Odelius (non verificato)

My correction above did not format correctly, so hopefully this will clarify:

The taxonomy term field output should be rewritten to include:
data-filter=".tid-{{ field_term__target_id }}"
or the filters won't have an object to target.

Sorry about the confusion. The code tag does not escape HTML elements.

Consenso Privacy
Profile picture for user alberto
Inviato da alberto Ven, 17/05/2019 - 20:18

In risposta a di Dwight Odelius (non verificato)

Hello Dwight, thank you very much for the edit ;-)

Drupal community is awesome by helping each other in every way. I will update the article with your suggestion as soon as I can :)


Consenso Privacy
Inviato da Tej Prakash (non verificato) Mar, 07/07/2020 - 11:41

Can you share views screenshot on my email-id. i am new in Drupal 8.

Consenso Privacy
Inviato da Robb (non verificato) Ven, 14/08/2020 - 11:55

Just wanted to add my thanks for this awesome post. I found I had to make a couple of minor tweaks:

  1. my_theme_preprocess_views_view__my_isotope instead of my_theme_preprocess_views_view__my_isotope_list
  2. (function($){ ... })(jQuery); instead of
    jQuery(document).ready(function($){ ... });

But you've saved me a ton of work!

Consenso Privacy
Profile picture for user alberto
Inviato da alberto Ven, 14/08/2020 - 14:48

In risposta a di Robb (non verificato)

Very glad that it was helpful to you.

I appreciate also your notes: the view theme template to override is up to you. I used the list view override because I found it easier to control elements and set classes into the Views UI.

While your version of the jquery function could also be better for compatibility and also recommended for last versions of jQuery, but it's much the same.


Consenso Privacy

Aggiungi un commento

Solo a uso interno: questo campo non verrà mostrato.

HTML ristretto

  • Elementi HTML permessi: <br> <p> <h2> <h3> <h4> <h5> <h6> <strong> <em> <code> <blockquote> <ul> <ol start> <li>
  • Linee e paragrafi vanno a capo automaticamente.
Dichiaro di aver preso visione dellaPrivacy Policy del sito e acconsento alle finalità ivi espresse.