RFC / WIP - html_attributes function #4405
Draft
+463
−0
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
An alternative implementation to #3930
Addresses:
This WIP pr demonstrates a html attribute merging strategy for html attributes, aria-attributes with special handling for
class
,style
data
andaria
attributes.I've currently focussed on the
HtmlAttributes::merge
function which returns the merged attributes array.Examples
See
./Tests/HtmlAttributesTest.php
for usage examplesThe return value of
HtmlAttributes::merge
should also be able to be used as an input forHtmlAttributes::merge
as demonstrated here:https://github.com/twigphp/Twig/pull/4405/files#diff-210291f849102679e6c0a1050d5bcd3076cf55b3cc9677c20fab26dcd15f543cR27-R75
Rendering Attributes
The
HtmlAttributes::renderAttributes
method that takes the output ofHtmlAttributes::merge
and creates the attribute string.This method:
null
attribute valuesclass
,style
anddata-controller
attribute valuesaria-*
boolean attribute values to'true'
'false'
strings.data-*
array valuesfalse
values (seearia-*
coercion above)true
boolean values./Tests/HtmlAttributesTest.php
demonstrate the return value ofHtmlAttributes::merge
andHtmlAttributes::renderAttributes
There was some consideration made to coerce
data-*
boolean values to string'true'
and'false'
but this was decided against. StimulusJs uses the following conditional to determine if adata-*-value
attribute istrue
orfalse
when internally coercing to a javascriptBoolean
.Illustrated here: https://codepen.io/leevigraham/pen/MWNOyLr
Challenges
The challenge with a
html_attributes
like function is that the merging strategy is arbitrary.class
andstyle
attributes are usually merged together. Other attributes override the previous values.Symfony UX twig components recommend Stimulus for interaction. Stimulus uses
data-controller
attributes for functionality. Thedata-controller
value can be a space delimited list of strings. In this case should the multipledata-controller
values be merged or overridden? For StimulusJs also applies todata-target
anddata-action
Alternative implementation ideas
Merge strategy options
Given the challenges with
data-controller
above maybe the method should take 2 arguments:In the example above the
$options
argument would be used to determine which values to merge. Other values would replace.Given the return value of
HtmlAttributes::merge
can also be used as the$attributes
argument ofHtmlAttributes::merge
the developer could callHtmlAttributes::merge
multiple times which would be the equivalent of multiple attribute arrays / argument unpacking.References in other platforms / frameworks:
Yii2 has a similar function: https://github.com/yiisoft/yii2/blob/master/framework/helpers/BaseHtml.php#L1966-L2046
The renderTagAttributes method has the following rules:
'aria' => ['role' => 'checkbox', 'value' => 'true']
would be rendered asaria-role="checkbox" aria-value="true
".'data' => ['params' => ['id' => 1, 'name' => 'yii']]
would be rendered asdata-params='{"id":1,"name":"yii"}
'.CraftCMS uses twig and provides an attr() twig method that implements renderTagAttributes. I've used this helper many times and the rules above are great. Especially the "Attributes whose values are null will not be rendered".
Vuejs v2 -> v3 also went through some changes for false values https://v3-migration.vuejs.org/breaking-changes/attribute-coercion.html. This aligns with "Attributes whose values are null will not be rendered." above.
TODO