The paragraph.html.twig template file doesn't have the current loop index available to it, so we have no idea what item is currently being rendered - it is useful sometimes to know what the index is, as we might want to set some different css classes or similar on specific indexes.

To work around this, I added a field hook in my template:

function mytheme_preprocess_field(&$variables) {
    if($variables['field_name'] == 'my_paragraph_field'){

     foreach($variables['items'] as $idx => $item) {
        $variables['items'][$idx]['content']['#paragraph']->index = $idx;
      }
    }
}

This enables me to access the index in the twig template using paragraph.index, but it would be preferable if this or something similar was available natively.

Comments

brynj created an issue.

miro_dietiker’s picture

I think field items also don't have it.

CSS offers some native support for children, from first/last/odd/even, ...

It could make sense to pass in the value, but i don't think we should output it by default in our template.

brynj’s picture

I'd agree that it shouldn't be output in the template by default, just made available to it.

My scenario was for a javascript carousel - I needed to set the first slide class to "active".

paulhuisman’s picture

nice fix @brynj

bygeoffthompson’s picture

Bravo @brynj, this node is exactly what I was looking for, and I agree, should be native.

My use case was needing to define unique classes for each iteration so I could use `paragraphs` and `bg image formatter` together easily. Thanks again!

alberto56’s picture

Although @brynj's solution works perfectly for twig templates, in that {{ paragraph.index }} now outputs the index, the index does not seem to be available in the preprocessor, or at least I can't find it!

idebr’s picture

osopolar’s picture

Closed the issue #2658192: Delta item as duplicate. There I posted a solution for nested paragraphs (D8), which is different to the one of @brynj. I like the workaround given here, maybe the other solution is helpful for @alberto56 as it happens in the pre-processing of the child paragraph.

See also issue #3006588: Suggestion of a more flexible way to define grid layouts for a complete example of nested paragraphs used for layout purposes.

gapple’s picture

I wanted to add the index to every paragraph type and not just a single field, so used this:

function THEME_preprocess_field(&$vars) {
  if (
    $vars['field_type'] == 'entity_reference_revisions'
    &&
    $vars['element']['#items']->getItemDefinition()->getSetting('target_type') == 'paragraph'
  ) {
    foreach ($vars['items'] as $idx => $item) {
      $vars['items'][$idx]['content']['#paragraph']->index = $idx;
    }
  }
}
jankap’s picture

@gapple could you perhaps show an example, how to reference to index in the paragraph--NAME.html.twig file?

I tried to use {{ paragraph.index }} like I can use paragraph.id() but it does not work for me.

gapple’s picture

@JankaP
{{ paragraph.index }} is the correct way to access the property. You may need to debug your code to ensure your hook is being called and applying the value to items as expected.

jankap’s picture

I only have to adapt the Theme name of the code snippet, right?

Is there a difference in working, depending how the paragraph..html.twig file is used?
I need it in a block within a view.
The custom paragraph...html.twig is working. But paragraph.index seems to be empty or not existing.

The index is for the whole paragraph field, right?
Or do I need to call if for a field inside of the paragraph?

Update:
I guess the problem is, that in a view block the variables do not have "items" but "view"

selwynpolit’s picture

@brynj,
thanks for this. It worked perfectly. I put the function into my .theme file, specified the field (field_video_accordions) I used to hold my paragraph, and then I was able to output the index in a twig template as in {{ paragraph.index }} which is zero based.
Further, I was able to use a conditional to be able to add a class to the first instance of the paragraph.

function danaprime_preprocess_field(&$variables) {
  if($variables['field_name'] == 'field_video_accordions'){
    foreach($variables['items'] as $idx => $item) {
      $variables['items'][$idx]['content']['#paragraph']->index = $idx;
    }
  }
}
{% if paragraph.index == 0 %}
  <li class="accordion-item is-active" data-accordion-item="">
{% else %}
  <li class="accordion-item" data-accordion-item="">
{% endif %}

Adding this in hopes it will make someone else's life a little easier.

mducharme’s picture

This is achievable in the twig template. See the edit on the OG post here: https://drupal.stackexchange.com/questions/245027/add-odd-and-even-to-fi...

smulvih2’s picture

#13 worked for me.

asarfaraz’s picture

#9 worked for me for all paragraphs

hcanning’s picture

Outstanding solution guys! Works great. Will paragraph.index render in `field.html.twig`. I can just get it outputting in `paragraph.html.twig`. Thanks