Skip to content

Twig: Example Component

Mike Mai edited this page Dec 12, 2018 · 22 revisions

Main Benefits

  1. Customizable HTML tag in the initially rendered markup
  2. Allowing the component's inner content to be overwritten via a Twig {% block block_name %} or just {{content}}. In either case, it's important to be agnostic about the details of the inner content.
  3. Consistent formatting

Code

Example 1: "Example" Component

{% set schema = bolt.data.components["@bolt-components-example"].schema %}

{% if enable_json_schema_validation %}
  {{ validate_data_schema(schema, _self) | raw }}
{% endif %}

{# Variables #}
{% set base_class = "c-bolt-example" %}
{% set attributes = create_attribute(attributes|default({})) %}
{% set inner_attributes = create_attribute({}) %}

{# Set up checks to validate that the component's prop values are allowed, based on the component's schema #}
{% set tag_options = schema.properties.tag.enum %}
{% set string_options = schema.properties.string.enum %}

{# Check that the component's current prop values are valid. if not, default to the schema default #}
{% set tag = tag in tag_options ? tag : schema.properties.tag.default %}
{% set string = string in string_options ? string : schema.properties.string.default %}
{% set boolean = boolean is sameas(true) or boolean is sameas(false) ? boolean : schema.properties.boolean.default %}

{# Array of classes based on the defined + default props #}
{% set classes = [
  base_class,
  string in string_options ? "#{base_class}--#{string}" : "",
] %}

{#
  Sort classes passed in via attributes into two groups:
  1. Those that should be applied to the inner tag (namely, "is-" and "has-" classes)
  2. Those that should be applied to the outer custom element (everything else EXCEPT c-bolt-* classes, which should never be passed in via attributes)
#}
{% set outer_classes = [] %}
{% set inner_classes = classes %}

{% for class in attributes["class"] %}
  {% if class starts with "is-" or class starts with "has-" %}
    {% set inner_classes = inner_classes|merge([class]) %}
  {% elseif class starts with "c-bolt-" == false %}
    {% set outer_classes = outer_classes|merge([class]) %}
  {% endif %}
{% endfor %}

{# Example component's custom element wrapper #}
<bolt-example
  {% if tag %} tag="{{ tag }}" {% endif %}
  {% if string %} string="{{ string }}" {% endif %}
  {% if boolean %} boolean {% endif %}
  {% if outer_classes %} class="{{ outer_classes|join(' ') }}" {% endif %}
  {{ attributes | without('class') }}
>
  <{{ tag }} {{ inner_attributes.addClass(inner_classes) }}>
    {% block children %}
      {{ content }}
    {% endblock %}
  </{{ tag }}>
</bolt-example>

Example 2: "Simple" Component

Similar to the example above, only this time with deliberately more prescriptive initial HTML (for comparison).

{% set schema = bolt.data.components["@bolt-components-simple"].schema %}

{% if enable_json_schema_validation %}
  {{ validate_data_schema(schema, _self) | raw }}
{% endif %}

{# Variables #}
{% set base_class = "c-bolt-simple" %}
{% set attributes = create_attribute(attributes|default({})) %}
{% set inner_attributes = create_attribute({}) %}

{# Set up checks to validate that the component's prop values are allowed, based on the component's schema #}
{% set string_options = schema.properties.string.enum %}

{# Check that the component's current prop values are valid. if not, default to the schema default #}
{% set string = string in string_options ? string : schema.properties.string.default %}
{% set boolean = boolean is sameas(true) or boolean is sameas(false) ? boolean : schema.properties.boolean.default %}

{# Array of classes based on the defined + default props #}
{% set classes = [
  base_class,
  string in string_options ? "#{base_class}--#{string}" : "",
] %}

{#
Sort classes passed in via attributes into two groups:
1. Those that should be applied to the inner tag (namely, "is-" and "has-" classes)
2. Those that should be applied to the outer custom element (everything else EXCEPT c-bolt-* classes, which should never be passed in via atttributes)
#}
{% set outer_classes = [] %}
{% set inner_classes = classes %}

{% for class in attributes["class"] %}
  {% if class starts with "is-" or class starts with "has-" %}
    {% set inner_classes = inner_classes|merge([class]) %}
  {% elseif class starts with "c-bolt-" == false %}
    {% set outer_classes = outer_classes|merge([class]) %}
  {% endif %}
{% endfor %}

{# Simple component's custom element wrapper #}
<bolt-simple
  {% if string %} string="{{ string }}" {% endif %}
  {% if boolean %} boolean {% endif %}
  {% if outer_classes %} class="{{ outer_classes|join(' ') }}" {% endif %}
  {{ attributes | without('class') }}
>
  <div {{ inner_attributes.addClass(inner_classes) }}>
    <div class="{{ base_class }}__inner">
      {{ content }}
    </div>
  </div>
</bolt-simple>
Clone this wiki locally