Drupal 8 Development - How to Loop Through Field Formatter Elements All-- I'm trying to wrap my head around Drupal 8 development, and I'm trying to create a very simple field formatter.  It's being applied to a multi-file field, and I'm just trying to display information for each file uploaded to a custom content type that uses this field. 

But-- I'm having issues figuring out exactly how to properly pass data from my PHP files to my Twig template. The code and Twig template below are displaying info about the two files uploaded to a page just fine, but as you can see, I'm not looping through an array of items; I'm just inserting the variable names for some metadata I'm trying to display for some file objects, yet it's looping through and displaying the info for each file uploaded to the page even though I'm not doing a Twig loop.  Also-- if I add HTML above or below the Twig template placeholders ({{uri}} and {{filename}}), the HTML is being duplicated for each file that has been uploaded to the page.

So long story short: how should I massage my code to pass data to Twig such that I can loop through it with a Twig loop (e.g., {% for item in items %}) and also prevent any additional markup in the Twig template from being duplicated?

NOTE: here is the original viewElements() function that I was using, and that was causing my issue; all the code after this block is the final code that actually works:

  public function viewElements(FieldItemListInterface $items, $langcode) {
    $element = array();
    foreach ($items as $delta =&gt; $item) {
    // Render each element as markup.
      $element[$delta] = array(
      '#items' =&gt; array(
      'uri' =&gt; file_create_url($item-&gt;entity-&gt;get('uri')-&gt;value),
      'filename' =&gt; $item-&gt;entity-&gt;get('filename')-&gt;value,
      '#theme' =&gt; 'video_file_display',
    );
   }
   return $element;
 }


From FieldFormatter PHP file:

public function viewElements(FieldItemListInterface $items, $langcode) {
$element[0] = array(
  '#theme' =&gt; 'video_file_display',
);
foreach ($items as $delta =&gt; $item) {
 $element[0]['#items'][] = array(
    'uri' =&gt; file_create_url($item-&gt;entity-&gt;get('uri')-&gt;value),
    'filename' =&gt; $item-&gt;entity-&gt;get('filename')-&gt;value,
  );
}
return $element;
}


From .module file (hook_theme):

function field_formatter_test_theme(){
  return array(
    'video_file_display' =&gt; array(
      'variables' =&gt; array(
        'items' =&gt; array(
          'uri' =&gt; NULL, 'filename' =&gt; NULL),
        ),
      'template' =&gt; 'video-file-display',
    ),
  );
}


Twig template:

&lt;h3&gt;Here is my page&lt;/h3&gt;
{% for item in items %}
  {{item.uri}}&lt;br/&gt;
  {{item.filename}}
{% endfor %}

{{ kint() }}


Sample page output:

Here is my page
Twig context array(15)


(and examining the kint output shows null values for 'uri' and 'filename')
You define N #theme render arrays, if you want to be able to control the output in a single template, you need to define only one #theme element and pass it either two array of values or an array of arrays with a uri and filename key each.

$element[0] = array(
  '#theme' =&gt; 'video_file_display',
);
foreach ($items as $delta =&gt; $item) {
  $element[0]['#items'][] = array(
    'uri' =&gt; file_create_url($item-&gt;entity-&gt;get('uri')-&gt;value),
    'filename' =&gt; $item-&gt;entity-&gt;get('filename')-&gt;value,
  );
}