2

I'm trying to follow the syntax in the docs: https://github.com/craftcms/contact-form/blob/v2/README.md to output a select. I tried all sorts of syntax but I couldn't get it right…

From the docs, I would have thought this would work, but it just adds the options as an attribute of the select field in the HTML.

{{
  tag(
    'select',
    {
      id: 'type',
      name: 'message[type]',
      options: [
        {
          label: 'option1',
          value: 'option1'
        }
      ],
      class: message and message.hasErrors('message.type')
        ? 'error'
    }
  )
}}

The HTML output I get from that:

<select id="type" class="" name="message[type]" options="[{...;}]"></select>

I know I could just code it up as "html" but I'd like the keep the markup consistent and it makes the validation cleaner. Any pointer in the right direction much appreciated!

Yann
  • 604
  • 2
  • 7
  • 16

2 Answers2

1

What I think you want.

I understand that you want to produce a dropdown selection using the tag() function, and you want to avoid just slapping in some HTML and calling it a day.

The HTML we want out of this...

A <select> tags options should be inside the element, as <option>s.
So the output we want is.

<select id="type" class="" name="message[type]">
   <option value="option1">Option1</option>
   <option value="option2">Option2</option>
</select>

tag() function vs the {% tag %} tag

We have two options for making a tag in Craft-Twig. The tag() function and the {% tag %} tag.

While they give use two routes to the same end...

  • tag() is better for when the tag has no innerHTML/innerText, or the contents are pulled from another function or API.
  • {% tag %} is better for when the tag has longer content, or that content is being dynamically generated.

I think {% tag %} is the better option for this situation, but I'll go through them both.

The tag() function

Documentation: Craft CMS - Functions - tag()

tag('tag_type',{options_object})
The tag_type is the <tag_type>. Everything else is optional.

The options_block may include two options that affect the inner contents of a tag:

  • text: "Woo!": Text will be HTML encoded and rendered inside your tag.
  • html: "<i>Yay!</i>": HTML to be slapped into your tag, with no safety-net.

Everything else is stringified and added as an attribute.
So id: "thinger becomes <tag id="thinger">

Why is your code doing this?

option={...} isn't one of tag()'s two 'inner stuff' options, so it's just turned into a string and slapped in as an attribute.

To get what you want with tag()

Just add your desired innerHtml as a string to the options_object's html key.

{{
  tag(
    'select',
    {
      html:"<option value="Option1">Option1</option><option value="Option2">Option2</option>"
    }
  )
}}

As you can see, though, that can be a bit cumbersome when you have long HTML to insert.

The {% tag %} tag

Documentation Craft CMS - tags -tag

{% tag %} works almost exactly like tag(), except it let's us put the 's contents inside {% tag %} and {% endtag %}.

It accepts one argument, the tag type ('element' below), and an optional object via with, with each key/value pair becoming attributes on the tag to create.

{% tag 'element' with {
   class: "some class"
   custom_attribute: "some value"
 }
%}
   Your html {{ 'and_Twig()'|upper }} here.
{% endtag %}

becomes

<element class="some class" custom_attribute="some value">Your html AND TWIG here.</element>

This is better suited for when you have verbose tag contents, or contents that are dynamically generated by other tags/functions.

To get what you want with {% tag %}

Just put your option tags inside the {% tag %}...{% endtag %}

{% tag 'select' with {
   id: 'type',
   name: 'message[type]',
 -%}
   <option value="option1">Option1</option>
   <option value="option2">Option2</option>
{%- endtag %}

But I don't want to HTML it up...

No problem!

{% tag 'select' with {
   id: 'type',
   name: 'message[type]',
 -%}
   {% tag('option', {
      text: "Option1"
      value: "option1"
   }) %}
   {% tag('option', {
      text: "Option2"
      value: "option2"
   }) %}
{%- endtag %}
  • Thanks so much for the very thorough answer! The actual syntax is slightly different, you might wanna update your answer: ```{% tag 'select' with { id: 'type', name: 'message[type]' } -%} {%- endtag %}``` Notice the extra minus sign in `-%}` and `{%- endtag %}` – Yann Jun 11 '22 at 23:48
  • Your welcome, and good catch on the tags, thanks. – Wesley Williams Jun 12 '22 at 04:59
0

This is how I do

{% set tags = tag('option', {
   value: '',
   text: 'Select an option'|t
}) %}

{% set opts = [
    'Option 1',
    'Option 2',
    'Option 3'
] %}

{% for opt in opts %}
    {% set tags = tags ~ tag('option', {
        value: opt,
        text: opt
    }) %}
{% endfor %}

{{ tag('select', {
    name: 'iAm',
    class: 'form-control',
    title: 'I Am',
    'aria-label': 'Select an option'|t,
    required: true,
    tabindex: 0,
    html: tags
}) }}

You can also

{% set opts = {
    '1', 'Option 1',
    '2', 'Option 2',
    '3', 'Option 3',
} %}

{% for val, lbl in opts %}
    {% set tags = tags ~ tag('option', {
        value: val,
        text: lbl
    }) %}
{% endfor %}

Leoncio
  • 1,479
  • 2
  • 16
  • 19