Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Helper function to make dealing with HTML attributes easier #3907

Open
mpdude opened this issue Nov 21, 2023 · 1 comment
Open

Helper function to make dealing with HTML attributes easier #3907

mpdude opened this issue Nov 21, 2023 · 1 comment

Comments

@mpdude
Copy link
Contributor

mpdude commented Nov 21, 2023

I'd like to discuss adding a new function, let's say attr(), to make juggling with HTML attributes easier.

I'm willing to work on the implementation given that the general idea is backed here and we can sketch out some details.

Motivation

One pattern I see coming up in Twig templates again and again is along the lines of...

{% set attr = attr ?? {} %}
{% set attr = attr|merge({ id, type, href, class }) %}
{% set attr = attr|merge({class: (attr.class|default('') ~ ' form-horizontal')|trim}) %}
{% set attr = attr|merge({ 'aria-disabled': 'true', 'onclick': 'event.preventDefault()' }) %}
{% set attr = attr|merge({ 'style': {
    'color': groupFontColor ? groupFontColor : null,
    'background-color': groupBackgroundColor ? groupBackgroundColor : null
}}) %}

Then a custom macro along the lines of <div {{ printAttributes.print(attr) }}>...</div> follows. This macro basically puts all the key-value pairs into a key="value" other-key="other-value" sequence.

Suggested syntax, thoughts

Be able to pass multiple hashes into the function to avoid |merge calls:

<a {{ attr({ id, rel, href, class }, disabled ? { 'aria-disabled': 'true' }) }}>

Here, the short-hand ternary for the second argument resolves to the '' (empty string) value. Maybe this should be interpreted as an empty array to allow this notation.

Then, maybe know about special attributes like class that might work better if values are converted to array first and then a deep merge is performed:

<div {{ attr({ class: ['zero', 'first'] }, { class: 'second' }, third ? { class: 'third' }) }}>

In the case of class, all values should be concatenated with spaces and the result being trimmed.

For style, the attribute value might be a hash by itself. It would be turned into a string by concatenating all values with a pattern like {key}: {value};:

<div {{ attr({ style: { color: 'red' }}, { style: { 'background-color': 'green' }}) }}> gives <div style="color: red; background-color: green;">

In this case, maybe latter attr.style keys should override former ones?

data key/value pairs might be converted to data-firstkey="firstvalue" data-secondkey="secondvalue".

In general, if that should matter, optimize for the use case of adding attributes or adding to styles, CSS classes and the like instead of unsetting/overriding or completely replacing them with latter values.

tbd

The following pattern of conditionally adding to attrs is still a bit cumbersome, probably due to the lack of a deep-merge operator:

{% set attr = attr ?? {} %}
{% if condition1 %}
  {% set attr = attr|merge({ class: ['foo'] }) %}
{% endif %}
{% if condition2 %}
  {% set attr = attr|merge({ class: ['bar'], style: { color: 'red' }}) %}
{% endif %}

With both conditions evaluating to true, ideally attr(attr) would be class="foo bar" style="color: red;". But that is not up to the attr() function but rather the merges performed earlier.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

1 participant