alphagov / govuk-frontend

GOV.UK Frontend contains the code you need to start building a user interface for government platforms and services.
https://frontend.design-system.service.gov.uk/
MIT License
1.18k stars 325 forks source link

`govukAttributes` macro doesn't output values that use Nunjucks' `safe` filter #4937

Closed querkmachine closed 7 months ago

querkmachine commented 7 months ago

Raised and investigated via support.

Description of the issue

The govukAttributes macro, when provided a map of key-value pairs, will fail to output values that have previously passed through the Nunjucks safe filter.

This appears to be because the output of the safe filter is (if not null) actually an object, which the govukAttributes macro is interpreting to be one of our first-party attribute configuration objects.

Steps to reproduce the issue

Use this code in a project using GOV.UK Frontend's Nunjucks macros. The use of Back Link component here is illustrative, this issue is present in all components that use govukAttributes.

{{ govukBackLink({
  attributes: {
    'data-text': 'Testing',
    'data-html': '<i>Testing</i>',
    'data-number': 123.45,
    'data-boolean': true,
    'data-safe-text': 'Testing' | safe,
    'data-safe-html': '<i>Testing</i>' | safe,
    'data-safe-number': 123.45 | safe,
    'data-safe-boolean': true | safe
  }
}) }}

Each of the safe filtered values as they're exposed by the dump filter. The safe filter appears to convert anything passed to it into a string.

// data-safe-text
{ "val": "Testing", "length": 7 }

// data-safe-html
{ "val": "<i>Testing</i>", "length": 14 }

// data-safe-number
{ "val": "123.45", "length": 6 }

// data-safe-boolean
{ "val": "true", "length": 4 }

Actual vs expected behaviour

(HTML output has been reformatted for easier reading.)

Actual output

<a 
  href="#"
  class="govuk-back-link"
  data-text="Testing"
  data-html="&lt;i&gt;Testing&lt;/i&gt;"
  data-number="123.45"
  data-boolean="true"
  data-safe-text=""
  data-safe-html=""
  data-safe-number=""
  data-safe-boolean="">
  Back
</a>

Expected output

<a 
  href="#"
  class="govuk-back-link"
  data-text="Testing"
  data-html="&lt;i&gt;Testing&lt;/i&gt;"
  data-number="123.45"
  data-boolean="true"
  data-safe-text="Testing"
  data-safe-html="<i>Testing</i>" <!-- maybe undesirable, but would be logically consistent -->
  data-safe-number="123.45"
  data-safe-boolean="true">
  Back
</a>

Environment (where applicable)