Hi,
I'm trying to figure out a way to access webform elements from webform.html.twig.
I need to style the form; wrapping some elements and adding bunch of styles
all I have in the webform.html.twig is "children" variable which renders the whole form, whereas I need to access every element individually.

I found a link on the web for webform-form.html.twig which might do what I need, however I can't find it in webform template folder
http://cgit.drupalcode.org/webform/tree/templates/webform-form.html.twig?id=1135b65031cd6cd195c2e638300e5ef945a6f652

Any help with this matter is much appreciated.

Comments

isamir created an issue. See original summary.

isamir’s picture

Issue summary: View changes
jrockowitz’s picture

Have you tried using hook_form_alter(), hook_form_webform_submission_form_alter(), or hook_form_webform_submission_WEBFORM_ID_form_alter().

isamir’s picture

yes, I already tried those before.
I will quote from a previous reply:

those are useful when you need to style individual element in the form (e.g email), whereas what I'm seeking is how to theme the form itself and access its elements within the form template. I also want to avoid fields theming (if I have a form with dozens of fields I will end up with dozens of twig files)

However, I have figured out a solutions for this situation (in case some one is interested).

  1. create a tempalte file for your form (ex. webform--newsletter.html.twig)
  2. there is a variable (element) where you can access each field of the form like this:
    {{ element.elements.YOUR_FIELD_NAME }}
  3. you need to output the form action (submit) at the end of the form like this:
    {{ element.actions }}
  4. the trick with this solution is that you need to output a couple of hidden form elements that is required for the form to be submitted:
    {{ element.form_build_id }}
    
    {{ element.form_id }}

    Update: you also need to print out the following variable

    {{ element.form_token }}

  5. ---

    My final form template looks like this:

    <div class="request-form">
      <div class="form-wrap clearfix">
        <div class="col-md-4 form-desc">
          {{ element.elements.form_description }}
        </div>
        <div class="col-md-8">
          <form{{ attributes }}>
            {{ title_prefix }}
            <div class="row">
              <div class="col-md-6">
                {{ element.elements.name }}
                {{ element.elements.email }}
                {{ element.elements.phone }}
              </div>
              <div class="col-md-6">
                {{ element.elements.message }}
                {{ element.form_build_id }}
                {{ element.form_token }}
                {{ element.form_id }}
                {{ element.actions }}
              </div>
            </div>
            {{ title_suffix }}
          </form>
        </div>
      </div>
    </div>
jrockowitz’s picture

Status: Active » Fixed
hanoii’s picture

This might be really good to document somewhere.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

ARUN AK’s picture

I tried this.. But not working. There is no variable called element inside webform.html.twig.

{#
/**
 * @file
 * Theme implementation for a 'webform' element.
 *
 * This is an copy of the webform.html.twig theme_wrapper which includes the
 * 'title_prefix' and 'title_suffix' variables needed for
 * contextual links to appear.
 *
 * Available variables
 * - attributes: A list of HTML attributes for the wrapper element.
 * - children: The child elements of the webform.
 * - title_prefix: Additional output populated by modules, intended to be
 *   displayed in front of the main title tag that appears in the template.
 * - title_suffix: Additional output populated by modules, intended to be
 *   displayed after the main title tag that appears in the template.
 *
 * @see template_preprocess_webform()
 * @see _webform_form_after_build()
 *
 * @ingroup themeable
 */
#}
<form{{ attributes }}>
  {{ title_prefix }}
  {{ children }}
  {{ title_suffix }}
</form>
jrockowitz’s picture

Please post your question to https://drupal.stackexchange.com/questions/tagged/webform or Drupal Slack.

vlad.dancer’s picture

@isamir, thanks a lot for this trick!
@ARUN AK, just call {{ kint() }} to see all available variables in the template.

Just in case, below is how I ended up with theming multistep webforms:

{% set step_key = element.progress['#current_page'] %}
{% set title_key = step_key ~ '_title' %}
{% set title_path = step_key ~ '.' ~ title_key  %}
{% set step_title = element.elements[step_key][title_key]  %}
{% set is_last_step = element.elements[step_key]['is_last_step'] ? true : false  %}

{# This trick is used to avoid a double render of the step's title #}
{% set step_title = step_title|merge({'#access': 'TRUE' })  %}

<form{{ attributes }} data-persist="garlic" data-destroy="false">
  {{ title_prefix }}

  {% if step_title is not empty %}
  <div class="step-title">
    <h3>{{ step_title['#text'] }}</h3>
  </div>
  {% endif %}

  <div class="wrapper">

    <div class="sidebar-wrapper">
      <div class="sidebar">
        {% if is_last_step %}
          {{ element.elements.actions.submit }}
        {% else %}
          <div class="button form-submit btn-default btn" disabled="true">Save Application</div>
        {% endif %}
        {{ element.progress }}
      </div>
    </div>

    <div class="form">
      {{ element.actions }}
      {{ element.elements }}
    </div>

  </div>
  {{ element.form_build_id }}
  {{ element.form_token }}
  {{ element.form_id }}
  {{ title_suffix }}
</form>
oltus’s picture

@isamir I tried your suggestion but there is no variable called element on webform template

{#
/**
* @file
* Theme implementation for a 'webform' element.
*
* This is an copy of the webform.html.twig theme_wrapper which includes the
* 'title_prefix' and 'title_suffix' variables needed for
* contextual links to appear.
*
* Available variables
* - attributes: A list of HTML attributes for the wrapper element.
* - children: The child elements of the webform.
* - title_prefix: Additional output populated by modules, intended to be
* displayed in front of the main title tag that appears in the template.
* - title_suffix: Additional output populated by modules, intended to be
* displayed after the main title tag that appears in the template.
*
* @see template_preprocess_webform()
* @see _webform_form_after_build()
*
* @ingroup themeable
*/
#}

Can you guide us where we can get the tpl to render the fields individually.

Maruthachala Moorthy E’s picture

Were you able to do a preview of the submission. I am rendering individual elements like you have mentioned above but the data are not viewable on Preview page. Any idea how to render those as well or should we include any item extra from element variable.
Seems overriding 'webform-submission.html.twig' is the way to render individual elements in our way....

TedWS’s picture

thanks to isamir.
However, the solution wasnt 100% working to me.
I have to make some adjustment on my own.

On webform-submission-form--{webform_machine_name}.html.twig

{#
/**
 * @file
 * Default theme implementation for a webform submission form.
 *
 * Available variables:
 * - form: The webform submission form.
 *
 * @ingroup themeable
 */
#}
{# {{ dump(form) }} #}


<div class="webform">
  <div class="form-wrap clearfix">
      <form{{ form.attributes }}>
        {{ title_prefix }}
        <div class="row">
          <div class="col-md-6">
            {{ form.elements.name }}
            {{ form.elements.email }}
            {{ form.elements.contact_number }}
            {{ form.elements.submission_origin }}
          </div>
          <div class="col-md-6">
            {{ form.elements.actions}}
          </div>
        </div>
          {{ form.form_build_id }}
          {{ form.form_token }}
          {{ form.form_id }}
      </form>
    </div>
  </div>
</div>
golubovicm’s picture

The solution vlad.dancer proposed works for me. I do have element array and I can render i.e.:

{{ element.progress }}

Also instead of {{ children }} (which is html) I can render {{ element }}, where element is an array.

However, if I want to i.e. render all the elements at once with excluding i.e. progress bar (and then render it later at some other position) this should work:

{{ element|without('progress') }}

but for some reason this is not working. Element is rendered completely and progress bar is not excluded. Any idea why?

Amit Dwivedi’s picture

To access and theme Progress bar and Form elements separately, below code can be used in webform.html.twig file -

<form{{ attributes }}>
  {{ title_prefix }}
  
  {% if element.progress %}
    <div class="webform-progress-bar-wrapper">
      {{ element.progress }}
    </div>
  {% endif %}

  <div class="webform-fields-wrapper">
    {{ element.elements }}
    {{ element.form_build_id }}
    {{ element.form_token }}
    {{ element.form_id }}
    {{ element.actions }}
  </div>

  {{ title_suffix }}
</form>
rkent_87’s picture

This works great for me, I'll also add that if you can't render the submit button for some reason, try this:

Default Submit Button reference:

{{ element.actions }}

Customized Submit Button reference:

{{ element.elements.actions }}

pbouchereau’s picture

For those wondering how to use the "without" twig filter like @golubovicm in #14, this actually works with the "form" variable inside the "webform-submission-form.html.twig" template.

raghwendra’s picture

For me #13 solution is working but not coming default actions / submit button of form. I tried the followings:
{{ element.actions }}
{{ element.elements.actions }}
{{ form.elements.actions}}
I also used the captcha.
Can you please share the solutions?