0

I wish to use an inline style to add a dynamically generated background image URL to a div, e.g.

  $build[0] = [
    '#type'       => 'container',
    '#attributes' => [
      'id' => 'thumbnail-image',
      // the example below is a YouTube thumbnail, to be cropped using other CSS
      'style' => sprintf('background-image: url("https://img.youtube.com/vi/1234567890/sddefault.jpg");', $video),
    ]
  ];
  return $build;

The XSS filtering silently drops style attributes. Can I disable that for an individual render array, or otherwise work around it?

Note: this is generating output for a Field Formatter, used in a view.

The official advice is:

If your markup needs any of the tags not in this whitelist, then you can implement a theme hook and/or an asset library. Alternatively, you can use the key #allowed_tags to alter which tags are filtered.

Things tried:

1) using a theme hook and a template

Here's my template:

<div class="test" style="background-image:url('https://img.youtube.com/vi/{{ video_id }}/sddefault.jpg');">Sample output</div>

It's working, except the style attribute is still being stripped out.

2) #allowed_tags (but it's not a tag, it's an attribute):

'#allowed_tags' => array_merge(\Drupal\Component\Utility\Xss::getAdminTagList(), ['style']),

Successful workaround:

This code is in a field formatter for views, so I overrode the default views template. The views templates allowed a style attribute to pass through as I would have expected.

Initially I made a template for one specific field, but the problem was I needed to access the values of a separate field too and it was proving hard/impossible to retrieve them with the row._entity variable.

So then I decided to use views-view-fields.html.twig instead, which gives access to all the fields. This took rather longer, but as my code had a couple of conditionals and some variables used more than once, on balance the end result is cleaner than doing everything in the UI. (It's worth leaving yourself a note in the view UI admin comment and any docs that the view field is overwritten.)

1

I'd use '#type' => 'inline_template' for this: You can do everything what you can do in a regular .twig file, just inlined in code:

  $build[0] = [
    '#type'       => 'inline_template',
    '#template'   => '<div id="thumbnail-image" style="background-image: url({{ foo }})">{{ bar }}</div>'
    '#context' => [
      'foo' => $youtube_thumbnail
      'bar' => $whatever
    ]
  ];
  return $build;

Here is a complete list of render elements / #type 's for render arrays. (For Forms API, here is the sub-list of FormRenderElements)

| improve this answer | |
  • Yep, I understand why an inline template is easier, but the problem is however I write the tag (render array, external twig file, inline_template, even using \Core\Render\Markup) the style attribute is being removed by the XSS Filter. – William Turrell Dec 29 '19 at 14:14
  • #type => markup is going through XSS filter, however the source of a Twig templates should not. (Can't test right now, but neither inline styles nor JS are usually filtered when written directly into Twig) – Hudri Dec 29 '19 at 14:25
  • My hunch is because it's a Field Formatter, maybe Views does something? (Think I might open an issue about it on drupal.org) – William Turrell Dec 29 '19 at 14:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.