Render Array Patterns
When to Use
When you need consistent rendering patterns across multiple controllers, blocks, or preprocess functions. Render arrays are Drupal's structured way to describe renderable content.
Reusable Render Patterns
| Pattern | Use When | Example |
|---|---|---|
| Theme hooks | Consistent markup for entity type | node.html.twig, user.html.twig |
| Render element plugins | Reusable form/page elements | Textfield, Details, Container |
| #type shortcuts | Common render patterns | #type => 'link', #type => 'dropbutton' |
| Template suggestions | Variations of same pattern | node--article--teaser.html.twig |
Decision
| If you need... | Use... | Why |
|---|---|---|
| Render link consistently | ['#type' => 'link'] |
Structured, cacheable, themeable |
| Render image consistently | ['#theme' => 'image'] |
Standard image render array |
| Custom render element type | Create render element plugin | Reusable across project |
| Complex repeated markup | Theme hook + template | Centralized markup pattern |
| Entity rendering | view_builder->view($entity) |
Consistent entity rendering |
Pattern
// WRONG: Duplicating markup in controllers/blocks
public function build() {
return [
'#markup' => '<a href="/node/1" class="custom-link">Link</a>',
];
}
// RIGHT: Structured render array
public function build() {
return [
'#type' => 'link',
'#title' => $this->t('Link'),
'#url' => Url::fromRoute('entity.node.canonical', ['node' => 1]),
'#attributes' => ['class' => ['custom-link']],
];
}
// Reusable render array factory method (service)
class RenderHelper {
public function buildCard(string $title, array $content): array {
return [
'#theme' => 'mymodule_card',
'#title' => $title,
'#content' => $content,
'#cache' => [
'contexts' => ['user.permissions'],
],
];
}
}
// Use in multiple controllers/blocks
$build[] = $this->renderHelper->buildCard('Title', $content);
Reference: core/lib/Drupal/Core/Render/Element/, core/modules/node/node.module (theme hooks), core/lib/Drupal/Core/Render/theme.api.php
Common Mistakes
- Hardcoded HTML in #markup — Use structured render arrays (
#type,#theme) for themability and cacheability - Duplicating render array structures — Create helper methods or services for repeated patterns
- Not setting cache metadata — Always set
#cachecontexts, tags, max-age for proper caching - Rendering entities manually — Use
entity_type.view_builderservice to render entities - Ignoring existing #type options — Check core render elements before creating custom ones