Add attributes to the render array I am trying to add some attributes to a render array. In Drupal 7, we can do this by adding a property in an array like the following.
$items[] = array('data' =&gt; $item_data, 'id' =&gt; 'someId'); // attribute = 'id'
$variables['subpanels'] = theme('item_list', array('items' =&gt; $items, 'title' =&gt; NULL, 'type' =&gt; 'ul'));

In Drupal 8, there's no #attributes property documented in Render Arrays in Drupal 8. How can I add this id as an attribute in a render array, with Drupal 8?
This is the code I am using so far.
mymoduleController.php
public static function _mymodule_f1($users_online) {
  $user = \Drupal::currentUser();

  $render_array_1 = array();
  $render_array_1['name'] = 'test-name';
  $render_array_1['header'] = t('test-header');
  $render_array_1['contents'] = array('#value' =&gt; '&lt;div class=&quot;test_options&quot;&gt;' . '&lt;a class=&quot;test_loading&quot; href=&quot;#&quot;&gt;&lt;/a&gt;'. '&lt;/div&gt;');

  $items = array();
  foreach ($users_online as $key =&gt; $value) {
    if ($key != 'total') {
      $items[] = array('#value' =&gt; '&lt;a class=&quot;' . $key . '&quot; href=&quot;#&quot;&gt;' .   $value['name'] . '&lt;/a&gt;', 'class' =&gt; array('status-' . $value['status']));
    }
  }
  //print_r($items);
  if ($items) {
    $item_list = array(
      '#theme' =&gt; 'item_list',
      '#items' =&gt; $items,
    );
    $render_array_1['footer'] = $item_list;
  }
  $render_array_1['text'] = array('#value' =&gt; t('T1') . ' (&lt;span class=&quot;online-count&quot;&gt;' . count($items) . '&lt;/span&gt;)');
  $image = [
   '#theme' =&gt; 'image',
   '#uri' =&gt; drupal_get_path('module', 'mymodule') . '/css/themes/images/loading.gif',
   '#width' =&gt; NULL,
   '#height' =&gt; NULL,
   '#class' =&gt; 'icon'
  ];

  $render_array_1['icon'] = $image;
  $mymodule_subpanel = array(
    '#theme' =&gt; 'mymodule_subpanel',
    '#subpanel' =&gt; $render_array_1
  );
  return $mymodule_subpanel;
}

mymodule.module
function mymodule_theme() {
  return array(
    'mymodule' =&gt; array(
      'variables' =&gt; array('mymodule' =&gt; NULL),
      'template' =&gt; 'mymodule',
    ),
   'mymodule_subpanel' =&gt; array(
     'variables' =&gt; array('subpanel' =&gt; NULL),
     'template' =&gt; 'mymodule-subpanel',
   ),
 );
}

function mymodule_preprocess_mymodule(&amp;$variables) {
  $items = array();
  $users_online = mymoduleController::f2();
  $render_items = mymoduleController::_mymodule_f1($users_online);
  $render_items['#attributes'] = array('id' =&gt; 'some_id'); //not working; unable to add id='some_id' in the &lt;li&gt; tag.
  //print_r($render_items);

  $items[] = $render_items;
  //print_r($items);

  $item_list = array(
    '#theme' =&gt; 'item_list',
    '#items' =&gt; $items, // array of render arrays.
    '#title' =&gt; NULL,
    '#list_type' =&gt; 'ul',
    '#attributes' =&gt; array('id' =&gt; 'mainpanel')
  );
  $variables['subpanels'] = $item_list;
}
Render arrays can contain render elements or theme templates.

Example for a render element:

'#type' =&gt; 'link'


and a theme template:

'#theme' =&gt; 'item_list'


Render elements have the parameter #attributes. This is defined in the base class Drupal\Core\Render\Element\RenderElement that all render and form elements are extended from.

That is not the case for templates in general. 

The template links for example has #attributes and handles this in template_preprocess_links() in /core/includes/theme.inc. 

The example from the question is item-list. This template has a variable #wrapper_attributes. You can see in the first line of the preprocess function how wrapper-attributes is transformed in an attributes object, which is then passed on to the twig template where it is placed in the list wrapper:

/**
 * Prepares variables for item list templates.
 *
 * Default template: item-list.html.twig.
 *
 * @param array $variables
 *   An associative array containing:
 *   - items: An array of items to be displayed in the list. Each item can be
 *     either a string or a render array. If #type, #theme, or #markup
 *     properties are not specified for child render arrays, they will be
 *     inherited from the parent list, allowing callers to specify larger
 *     nested lists without having to explicitly specify and repeat the
 *     render properties for all nested child lists.
 *   - title: A title to be prepended to the list.
 *   - list_type: The type of list to return (e.g. "ul", "ol").
 *   - wrapper_attributes: HTML attributes to be applied to the list wrapper.
 *
 * @see https://www.drupal.org/node/1842756
 */
function template_preprocess_item_list(&amp;$variables) {
  $variables['wrapper_attributes'] = new Attribute($variables['wrapper_attributes']);
    foreach ($variables['items'] as &amp;$item) {
    $attributes = array();
    // If the item value is an array, then it is a render array.
    if (is_array($item)) {
      // List items support attributes via the '#wrapper_attributes' property.
      if (isset($item['#wrapper_attributes'])) {
        $attributes = $item['#wrapper_attributes'];
      }


The template item_list has also the variable attributes, which is passed on to the twig template. Here you can see how this all ends up in the html markup, including the attributes of the items, which are collected for each item from wrapper-attributes in preprocess:

item-list.html.twig

{#
/**
 * @file
 * Theme override for an item list.
 *
 * Available variables:
 * - items: A list of items. Each item contains:
 *   - attributes: HTML attributes to be applied to each list item.
 *   - value: The content of the list element.
 * - title: The title of the list.
 * - list_type: The tag for list element ("ul" or "ol").
 * - wrapper_attributes: HTML attributes to be applied to the list wrapper.
 * - attributes: HTML attributes to be applied to the list.
 * - empty: A message to display when there are no items. Allowed value is a
 *   string or render array.
 * - context: A list of contextual data associated with the list. May contain:
 *   - list_style: The custom list style.
 *
 * @see template_preprocess_item_list()
 */
#}
{% if context.list_style %}
  {%- set wrapper_attributes = wrapper_attributes.addClass('item-list--' ~ context.list_style) %}
  {%- set attributes = attributes.addClass('item-list__' ~ context.list_style) %}
{% endif %}
{% if items or empty -%}
  &lt;div{{ wrapper_attributes.addClass('item-list') }}&gt;
    {%- if title is not empty -%}
      &lt;h3&gt;{{ title }}&lt;/h3&gt;
    {%- endif -%}
    {%- if items -%}
      &lt;{{ list_type }}{{ attributes }}&gt;
        {%- for item in items -%}
          &lt;li{{ item.attributes }}&gt;{{ item.value }}&lt;/li&gt;
        {%- endfor -%}
      &lt;/{{ list_type }}&gt;
    {%- else -%}
      {{- empty -}}
    {%- endif -%}
  &lt;/div&gt;
{%- endif %}


Btw. the wrapper is only placed in the classy theme, the base theme doesn't use this.

Conclusion:

Templates don't have attributes by default. As the examples show, they can handle them like render elements, under a different variable name or not at all.