Skip to main content

An Introduction to Drupal's Render Arrays

Front-end Development
Drupal

Drupal is a content management system, and one of the key purposes of a CMS is to deliver content in a readable form. That could be through a feed or API in a headless context, but the most common implementation is for the CMS to produce HTML to be delivered to a web browser.

Render arrays are Drupal's core mechanism for producing this output. In this article, we'll dig into how render arrays work and give an introduction to how to use one.

Why render arrays?

HTML is just specially-formatted text, so producing output from a CMS means constructing a text string. PHP is pretty good at manipulating text, and we can easily concatenate fragments of text together to form an HTML document.

In days of yore, Drupal did just that to construct a page. Each function that produced a page element would build some HTML text and return that, and other functions would stitch those together and pump them out to the web browser. This works.

However, there are plenty of drawbacks to that approach. Text alone is hard to scan for security vulnerabilities. It's easy for text to contain malformed HTML, especially when joining together big nested lists of things. Text is hard to alter later if other parts of the system want to change something.

The render system is designed to attack these problems. Instead of creating HTML snippets, Drupal module functions create arrays of structured information, which are later processed by the theme and render systems to produce HTML at the last possible minute. Arrays are easy to inspect and manipulate, so things stay transparent as long as they can.

What does a render array look like?

As you might expect, a render array is a PHP associative array structure. Some keys are interpreted in predefined ways. For example, the key #markup tells Drupal to treat the value as HTML to be placed on the page. The simplest possible render array, then, is an array with just that key:

  public function page() {
    return [
      '#markup' => '<p>The simplest <b>render array</b> possible.</p>',
    ];
  }

This will produce a page with that paragraph on it:

Output showing "The simplest render array possible."

There are of course many other meaningful keys. #plain_text is nearly as simple, but will additionally escape all of the text provided to it, making this a safe option for user-provided content.

  public function page() {
    return [
      '#plain_text' => '<p>This shows how <b>plain_text</b> differs from <b>markup</b> in a render array.</p>.',
    ];
  }

 

Output showing text with visible HTML tags.

Render elements

In addition to producing output using these native render array keys, we can call on the power of render elements to produce more complicated output. Render elements are defined by plugins, and tell the render system how to handle additional keys in render arrays. To use one, we call it by its machine name using the #type key.

  public function page() {
    return [
      '#type' => 'html_tag',
      '#tag' => 'p',
      '#value' => 'This example shows how a <b>render element</b> works.',
    ];
  }

This uses core's HtmlTag render element, which simply creates an HTML element with the name specified in #tag and the contents given in #value.

Output showing "This example shows how a render element works."

More complicated array structures

These simple examples only scratch the surface, of course. For a little peek into what is to come, let's see what happens when you put a render array inside another one.

  /**
   * Create and display a render array.
   */
  public function page() {
    return [
      '#type' => 'container',
      'heading' => [
        '#type' => 'html_tag',
        '#tag' => 'h1',
        '#value' => 'Nested arrays',
      ],
      'content' => [
        [
          '#type' => 'html_tag',
          '#tag' => 'p',
          '#value' => 'Array keys starting with # are treated as render element properties.',
        ],
        [
          '#type' => 'html_tag',
          '#tag' => 'p',
          '#value' => 'All the other keys become children.',
        ],
      ],
    ];
  }

Note that some of the keys here start with a # character, and others do not. This leading # is special to Drupal. It tells the render system to treat what comes next as a render element property: that is, something that either is a native render array feature (like #markup, #plain_text, and #type), or is something that a render element understands and can work with. Anything that does not have this character is not processed.

So what happens to array items that don't have the # prefix? They become children of the render array, and are expected to be render arrays themselves. When it comes time to produce HTML for the browser, the interior render arrays will be processed first, and their results will then be wrapped by the parent render array element (assuming that element supports this, which most do when it makes sense).

In our example here, the outmost render element is a Container which creates a <div> HTML element. Then the keys heading and content contain further render arrays that will be displayed as the inner content of the element. It doesn't matter to Drupal what we call these child arrays, so they can be named however it makes sense.

In particular, the child array keys can just be numbers when it makes sense, as for example, we do here with the two children of the content array (which implicitly have the keys 0 and 1).

So once this is all processed, we get a containing <div> with the <h1> and two <p> tags inside it:

Example showing a heading and two paragraphs.

Next steps

These examples show the basic structure of a render array and a couple of things you can do with them. In the next article, we'll explore the standard properties you can use in nearly any render array and some of the powerful reasons this system exists.

For further reference, see the Drupal documentation on render arrays.