---
url: /html.md
---
# HTML Elements

## i:img (images)

Renders an image for a product, category, article, etc. Not used for static template images (icons, etc.).

Handles thumbnail URL generation, retina display support, and automatic image alt text.

When multiple dimensions are specified, a srcset is generated that can be used in combination with the HTML5 *sizes* attribute. If the *sizes* attribute is omitted, *width* and *height* attributes are set based on the actual resulting image dimensions.

If the **alt** attribute is not specified, it is automatically populated from the image description or the product/variant/... name.

The output differs depending on the device (retina/non-retina) and load order (first/subsequent). **Retina images may overflow -- you must handle this in CSS**, for example with *max-width:100%;max-height:100%*.

```twig
<i:img src="zbozi.img" format="800x600" />
<i:img src="zbozi.img" format="800x600,300x200" sizes="(min-width: 500px) 50vw, 100vw" />
```

**Attributes**

| Attribute | Required | Description |
|---|---|---|
| **src** | **yes** | Twig object |
| **format** | **yes** | image dimensions |
| sizes | *no* | same as HTML5 sizes -- required when multiple dimensions are specified |
| watermark | *no* | image will have a watermark |
| fill | *no* | pad the image with white borders |
| vector | *no* | use PNG/SVG |
| transparent | *no* | image has transparency |
| quality | *no* | low/normal/high/lossless (default: normal) |
| lazyload | *no* | *src* and *srcset* as data attributes |
| class | --- | CSS class |

### Image Zoom

Wrap an image in a link with **@** as the href -- it will be replaced with the appropriate URL. The link may contain **only one image**. If you need a conditional, use two separate links.

```twig
<a href="@"><i:img src="zbozi.img" format="800x600" /></a>
<a href="@"><i:img src="zbozi.img" format="800x600" sizes="(min-width: 500px) 50vw, 100vw" /></a>
```

## i:img-360 -- 360 Product View

Renders the 360° spin player for a product that has 360° frames (`product.images360`). The player is a
100 %-wide box that keeps the frames' aspect ratio from the first paint, shows the first frame as a
placeholder until the library has loaded, and re-draws itself whenever its width changes (a slider
showing the slide, a fancybox dialog, a phone rotating). Give it a container of the width you want; no
sizing CSS is needed. A product without frames renders nothing, so wrap the tag only when the
surrounding markup (a slide, a thumbnail) must be conditional too.

```twig
{% if product.images360 is not empty %}
    <i:img-360 product="product" format="400x400,800x800" sizes="(min-width: 768px) 400px, 100vw" />
{% endif %}
```

**Attributes**

| Attribute | Required | Description |
|---|---|---|
| **product** | **yes** | Product object |
| format | *no* | frame dimensions (same as i:img). Default: \[500x500, 1000x1000, 1500x1500, 2000x2000]; the library picks the size closest to the screen width |
| sizes | *no* | responsiveness of the placeholder (same as i:img) -- required when multiple dimensions are specified |
| zoom | *no* | magnifier zoom, 2–5 or `off` (default: 3); the library disables the magnifier on touch devices |
| no-steps | *no* | hide the forward/backward step buttons |
| no-fullscreen | *no* | hide the fullscreen button (the fullscreen view carries the same prev/play/next bar as the inline player) |
| no-play | *no* | hide the play/stop button |
| autoplay | *no* | start rotating as soon as the frames are loaded (the play button starts as "pause") |
| hide-logo | *no* | hide the 360 view logo overlay shown before the first drag |
| bottom-circle | *no* | show the bottom 360 circle |
| lazyload | *no* | load the library and frames only when the element enters the viewport (see the strategies below) |
| lazyload="click" | *no* | load the library and frames only when the element is clicked (a 360 icon marks the placeholder) |
| hidden | *no* | render the player hidden (`display:none`); it is activated only by `window.image360.push()` -- see below |
| class | *no* | CSS class added to the `.img-360-container` element (used to target the player from fancybox `data-src`) |

**Loading strategies**

| Strategy | Markup | Frames download |
|---|---|---|
| eager | `<i:img-360 product="product" />` | on page load |
| viewport | `lazyload` | when the box scrolls into view (200 px ahead in the white-label bundle, at the edge with the legacy inline helper) |
| click | `lazyload="click"` | when the visitor clicks the placeholder |
| on demand | `hidden` + `window.image360.push(element)` | when your JS activates it (slider slide shown, dialog opened) |

`window.image360.push(element)` takes the `.image-360-hidden` element (or its `.image-360` counterpart)
and initializes it; before the storefront bundle has booted it queues the element and processes it at
boot, so it is safe to call from template JS at any time. Pushing an already initialized element does
nothing.

### In a slider

Put the player into a slide and activate it when the slide is about to be shown, so the frames are
downloaded only by visitors who reach the slide. The thumbnail strip gets the first frame via
`product.firstImage360`. While the pointer is down on the player, disable the slider's own swipe so a
horizontal drag rotates the product instead of changing the slide (slick example):

```twig
{% if product.images360 is not empty %}
    <div class="item item-360">
        <i:img-360 product="product" hidden format="400x400,800x800" sizes="(min-width: 768px) 400px, 100vw" />
    </div>
{% endif %}
```

```js
function activate360InSlide(slick, index) {
    var el = slick.$slides.eq(index).find('.image-360-hidden')[0];
    if (el) {
        window.image360 = window.image360 || [];
        window.image360.push(el);
    }
}

$('.slider')
    .on('init', function (e, slick) { activate360InSlide(slick, slick.currentSlide); })
    .on('beforeChange', function (e, slick, current, next) { activate360InSlide(slick, next); })
    .slick({ fade: true, /* … */ });

$('.item-360 .img-360-container').on('mousedown touchstart', function () {
    $('.slider').slick('slickSetOption', 'swipe', false);
});
$(document).on('mouseup touchend touchcancel', function () {
    $('.slider').slick('slickSetOption', 'swipe', true);
});
```

Because the player renders hidden until the slide is shown, make the placeholder visible so the slide
has its height from the first paint (the box keeps the frames' aspect ratio):

```scss
.item-360 .image-360-hidden { display: block; }
```

### In a fancybox lightbox (3.5)

Add a thumbnail link of type `inline` pointing at a hidden player; the storefront bundle activates the
player when the lightbox opens and re-draws it when its slide is shown. The link's `data-options`
switch off fancybox's own touch gestures and the click-to-close on that slide only, so dragging the
product does not pan or close the lightbox. The dialog content gets its width from the viewport so
that the box fits the viewport height as well (`min(92vw, (100vh - 20px) * ratio)`; the frames'
ratio is emitted as `--img360-ratio` on the `.img-360-container`). The rule has zero specificity,
so any `.fancybox-slide .img-360-container { width: … }` in the template wins.

```twig
<a data-fancybox="product-gallery" data-type="inline" data-src=".fancybox-360" href="javascript:;"
   data-thumb="{{ product.firstImage360.url({width:150,height:150,fill:true}) }}"
   data-options='{"touch": false, "clickSlide": false, "clickContent": false}'>
    <i:img src="product.firstImage360" format="350x350" />
</a>

<div hidden>
    <i:img-360 product="product" hidden class="fancybox-360" format="500x500,1000x1000" sizes="(min-width: 768px) 1000px, 100vw" />
</div>
```

Keep the lightbox player inside a `hidden` wrapper: the bundle initializes it as soon as the lightbox
opens (so the frames preload while the visitor still looks at the first photo), which makes the
player element itself visible; fancybox moves only the `.img-360-container` into the dialog and puts
it back on close, so the wrapper keeps it off the page the whole time.

The same player can be both the slider slide and the lightbox slide only by rendering it twice (one
`<i:img-360>` per place): fancybox moves its inline content into the dialog and back, so a single
element cannot live in both.

## i:video

```twig
{%for video in zbozi.videa%}
    <i:video src="video" width="400" height="300" />
{%endfor%}
{%for video in zbozi.videa%}
    <i:video src="video" width="400" height="300" class="embedded_video" />
{%endfor%}
```

**Attributes**

| Attribute | Required | Type | Description |
|---|---|---|---|
| **src** | **yes** | twig | Twig object |
| width | no | int | width in pixels (no units) |
| height | no | int | height in pixels (no units) |
| controls | no | string | `true` / `false` |
| loop | no | string | `true` / `false` |
| color | no | string | HEX color code for the icon |
| autoplay | no | | |
| class | --- | --- | CSS class |

## i:dynamic (attribute) -- dynamic section definition

Wrapping a section of code in an element with the *i:dynamic* attribute defines that this section needs to be dynamically updated from JavaScript. The attribute must list the variables used -- only these variables will be available inside the element (similar principle to a Twig [macro](https://twig.symfony.com/doc/1.x/tags/macro.html)).

Adding the *i:dynamic* attribute does not change the code's behavior -- the output remains the same. The only difference is a new attribute in the resulting HTML that enables reloading part of the page from JavaScript.

When reloading, you can also pass additional custom variables as "arguments". These are then available in the template via the "arguments" array. A typical use case is reloading a section that shows variant-specific information -- the newly selected variant can be passed as an argument.
Arguments are intended only for refining the selection and **cannot be used** to load entirely new content. The URL is public, so if an argument carried e.g. an order number, anyone could change the URL to see details of any order. For variant IDs and similar data, manual URL changes are harmless.

```twig
<div i:dynamic="cart,product" class="cart-items-table"> {# class is not required and can be anything #}
    {% if arguments['variant']|default(product.variant.id) %}
        abc
    {% endif %}
</div>
```

```javascript
$('.cart-items-table').reload(); // reload by class

$('.cart-items-table, .second-dynamic-div').reload(); // reload multiple sections at once

$('.cart-items-table').reload({
    callback: function() {
        alert('načteno!');
    }
});

$('.cart-items-table').reload({
    callback: function() {
        alert('načteno!');
    },
    arguments: {
        variant: 123
    }
});

$('.cart-items-table').reload({
    after:function(callback){
        // code that runs after the loading animation but before the actual reload
        // the reload is triggered by calling the callback
        // useful for async actions where you want the loading animation but delay the reload until completion
        callback();
    }
});
```

## i:dynamic (tag) -- dynamic section definition

Wrapping a section of code in an `<i:dynamic>` element defines that this section can be dynamically updated from JavaScript (automatically or manually).

The tag can be used for:

* reloading the element's content triggered by a JavaScript call
* deferring content generation until the element enters the viewport (lazy="auto")
* deferring content generation until explicitly requested from JavaScript (lazy="manual")

The *variables* attribute must list the variables used -- only these variables will be available inside the element (similar principle to a Twig [macro](https://twig.symfony.com/doc/1.x/tags/macro.html)).

```twig
{# content is rendered immediately with the page and can be refreshed from JavaScript #}
<i:dynamic variables="cart,product" class="cart-items-table"> {# class is not required and can be anything #}
    <h4>{{ product.name }}</h4>
</i:dynamic>

{# content is not rendered with the initial page load; it loads automatically when the element enters the viewport and can be refreshed from JavaScript #}
<i:dynamic variables="cart,product" lazy="auto" class="cart-items-table">
    <h4>{{ product.name }}</h4>
</i:dynamic>

{# content is not rendered with the initial page load; it loads only when reload() is called from JavaScript #}
<i:dynamic variables="cart,product" lazy="manual" class="cart-items-table">
    <h4>{{ product.name }}</h4>
</i:dynamic>
```

## i:map -- interactive map

The goal is to unify and simplify embedding maps in templates. The map automatically selects zoom and center based on the inserted points (**unless explicitly defined!**).

The map is rendered via mapy.cz, but support for additional map providers will likely be added in the future for language versions, etc. The template syntax is unified, and adding Google Maps support should not require any template changes.

```twig
<i:map grayscale class="map-class">
    <i:map-point address="Drtinova 10, Praha" icon="/images/logo.svg" size="40x50" header="Otevírací doba" tags="praha,kartou">
        Po: 08:00-18:00<br/>
        Út: 08:00-18:00<br/>
        St: 08:00-18:00<br/>
        Čt: 08:00-18:00<br/>
        Pá: 08:00-18:00<br/>
    </i:map-point>
    <i:map-point lat="50.65" lon="14.1456" icon="/images/logo.svg" size="40x50" label="Centrála" tags="usti,kartou"/>
    <i:map-point lat="51.00" lon="15.000" icon="/images/logo.svg" size="40x50" tags="andelka">
        <strong>{%trans%}Otevírací doba{%endtrans%}</strong> <br>
        08:00-18:00
    </i:map-point>

    {% for location in locations %}
        <i:map-point lat="{{location.lat}}" lon="{{location.lon}}" />
    {% endfor %}
</i:map>
```

```html
<!-- generated output -- subject to change! -->

<div class="map-class global-map grayscale">
    <span data-header="Otevírací doba" data-tags="praha,kartou" data-gps="50.0255597,14.5510733" data-icon="/1585575662/images/logo.svg" data-lat="50.0255597" data-lon="14.5510733">
        Po: 08:00-18:00<br>
        Út: 08:00-18:00<br>
        St: 08:00-18:00<br>
        Čt: 08:00-18:00<br>
        Pá: 08:00-18:00<br>
    </span>
    <span data-lat="50.65" data-lon="14.1456" data-label="Centrála" data-tags="usti,kartou" data-icon="/1585575662/images/logo.svg"></span>
    <span data-lat="51.00" data-lon="15.000" data-tags="andelka" data-icon="/1585575662/images/logo.svg">
        <strong>Otevírací doba</strong> <br>
        08:00-18:00
    </span>
    <div class="mapycz" style="height:400px"></div>
</div>
```

**i:map Attributes**

| Attribute | Required | Description |
|---|---|---|
| lat="" | *no* | latitude of the map center |
| lon="" | *no* | longitude of the map center |
| zoom="" | *no* | default map zoom |
| height="" | *no* | default map height (*400px*) |
| controls="off" | *no* | hide map controls |
| grayscale | *no* | |
| clusters="" | *no* | default distance for markers in a cluster (*40*) |
| cluster-class="" | *no* | custom class for the cluster |
| view="" | *no* | basic / hybrid / aviation / tourist / winter (default: *basic*) |
| view-layers="basic,aviation" | *no* | enable map layer switching -- basic / hybrid / aviation / tourist / winter (default: *"basic,aviation,hybrid,tourist,winter"*) |

**i:map-point Attributes**

| Attribute | Required | Description |
|---|---|---|
| lat="" and lon="" | **yes** | point coordinates. **Either lat/lon or address must be provided** |
| address="" | **yes** | point address. **Either lat/lon or address must be provided** |
| icon="/images/home.svg" | *no* | |
| size="20x20" | *no* | custom marker size. Default size: 23x32 |
| label="Centrala" | *no* | hover title |
| header="Opening hours" | *no* | card title |
| tags="praha" | *no* | tags separated by commas |
| code="xxx" | *no* | marker identifier |

### Custom Cluster Class

`<i:map cluster-class="embed-map-cluster"></i:map>`

cluster-class overrides the original class and creates new classes for the cluster.

**Attributes**

| Class | Description |
|---|---|
| **embed-map-cluster** | general class for all clusters |
| **embed-map-cluster-small** | < 10 points |
| **embed-map-cluster-medium** | < 40 points |
| **embed-map-cluster-large** | > 40 points |

### Opening a POI Externally

Call `window.mapComponent.openMarkerCard(code)` to open any POI detail.

```twig
<button type="button" class="show-marker-detail" data-code="simplia">Simplia</button>
<button type="button" class="show-marker-detail" data-code="test">Testovaci</button>

<i:map class="marker-map">
    <i:map-point address="Drtinova 10, Praha" code="simplia">
        Po: 08:00-18:00<br/>
        Út: 08:00-18:00<br/>
        St: 08:00-18:00<br/>
        Čt: 08:00-18:00<br/>
        Pá: 08:00-18:00<br/>
    </i:map-point>
    <i:map-point lat="51.00" lon="15.000" code="test">
        <strong>{%trans%}Otevírací doba{%endtrans%}</strong> <br>
        08:00-18:00
    </i:map-point>
</i:map>
```

```html
<script type="text/javascript">
    Array.prototype.forEach.call(document.querySelectorAll('.show-marker-detail'), function (el) {
        el.addEventListener('click', function (e) {
            e.preventDefault();

            var targetElement = e.target || e.srcElement;

            window.mapComponent.openMarkerCard('.marker-map', targetElement.dataset.code);
        });
    });
</script>
```

### Filtering Map Points

Filtering between tag arrays uses **AND** logic; within each tag array, **OR** logic is used. See the example: *Praha* **or** *Usti* **AND** *kartou* (card payment).

**window.mapComponent.filter Parameters**

| Attribute | Required | Description |
|---|---|---|
| selector | **yes** | map selector, e.g. **.global-map** |
| filter | **yes** | array of tag arrays |
| boolean | **no** | auto-center map on filtered POIs. **Default: false** |

```html
<script type="text/javascript">
    window.mapComponent.filter('.filter-map', [['praha', 'usti'], ['kartou']], true);
</script>
```

### Route Planning

Creates a URL via api.mapy.cz for route planning.

**i:map-route-link Attributes**

| Attribute | Required | Description |
|---|---|---|
| lat="" and lon="" | **yes** | point coordinates. **Either lat/lon or address must be provided** |
| address="" | **yes** | point address. **Either lat/lon or address must be provided** |

```twig
<i:map-route-link lat="50.7700158" lon="15.0595950">Popisek</i:map-route-link>
```

```html
<!-- generated output -- subject to change! -->

<a class="map-route-link" data-lat="50.7700158" data-lon="15.0595950" href="//mapy.cz/?planovani-trasy&amp;rc=95ra0x1qpF&amp;rs=&amp;rs=coor&amp;ri=&amp;ri=&amp;mrp=&amp;mrp={&quot;c&quot;:111}">
    Popisek
</a>
```

### Link to mapy.cz

Creates a URL to a POI on mapy.cz.

```twig
<i:map-link search="Helveti.cz">Helveti</i:map-link><br>
<i:map-link search="Jadi.cz, Praha">Jadi.cz Praha</i:map-link><br>
<i:map-link search="Jadi.cz, Liberec">JAdi.cz Liberec</i:map-link><br>
<i:map-link search="Jadi.cz">Jadi.cz</i:map-link><br>
<i:map-link search="Vítkova 244/8, Praha">Adresa</i:map-link>
```

```html
<!-- generated output -- subject to change! -->
<a class="map-link" href="//mapy.cz/zakladni?x=14.446071624756&amp;y=50.090213775635&amp;id=12903247&amp;source=firm">Helveti</a><br>
<a class="map-link" href="//mapy.cz/zakladni?x=14.429894447327&amp;y=50.081184387207&amp;id=12914136&amp;source=firm">Jadi.cz Praha</a><br>
<a class="map-link" href="//mapy.cz/zakladni?x=15.056777954102&amp;y=50.770107269287&amp;id=2099659&amp;source=firm">JAdi.cz Liberec</a><br>
<a class="map-link" href="//mapy.cz/zakladni?x=15.172479629517&amp;y=50.72388458252&amp;id=726263&amp;source=firm">Jadi.cz</a><br>
<a class="map-link" href="//mapy.cz/zakladni?q=V%C3%ADtkova+244%2F8%2C+Praha">Adresa</a>
```

## i:banners

Template for unified banner output.

In the examples below, the `i:****` tags are the important part -- the rest of the template markup will differ per shop due to legacy code.

```twig
<i:banners source="repository.banner.findBy({sectionCode: 'testovaci'})" plugin="swiper">
    <source format="1150x630" src="desktop"/>
</i:banners>
```

```html
<!-- generated output -- subject to change! -->

<div class="banner swiper-container">
    <div class="banner-wrap swiper-wrapper">
        <div class="banner-item banner--item__1 banner--item__first swiper-slide">
            <picture>
                <img width="1150" height="630"
                          srcset="//i00.eu/img/999997/1150x630a/562ojxe8/2229.webp 1x,//i00.eu/img/999997/2300x1260/25nkjd5z/2229.webp 2x"
                          src="//i00.eu/img/999997/1150x630a/562ojxe8/2229.webp">
            </picture>
        </div>
        <div class="banner-item banner--item__2 banner--item__last swiper-slide">
            <picture>
                <img class="auto-lazyload swiper-lazy" width="1150" height="599"
                          data-srcset="//i00.eu/img/999997/1150x630a/a7mwzmns/2237.webp 1x,//i00.eu/img/999997/2300x1260/b9whiv1f/2237.webp 2x"
                          src="//i00.eu/img/999997/1150x630a/a7mwzmns/2237.webp"
                          data-src="//i00.eu/img/999997/1150x630a/a7mwzmns/2237.webp"
                          srcset="//i00.eu/img/999997/1150x630a/a7mwzmns/2237.webp 1x,//i00.eu/img/999997/2300x1260/b9whiv1f/2237.webp 2x"
                          data-loaded="true">
            </picture>
        </div>
    </div>
</div>
```

Example using an inner wrapper div.

```twig
<i:banners source="repository.banner.findBy({sectionCode: 'testovaci'})" wrap="div.wrap.www-rap">
    <source format="1150x630" src="desktop"/>

    <h2 data-role="title"></h2>
    <div data-role="description"></div>
    <div data-role="cta"></div>
</i:banners>
```

```html
<div class="banner">
    <div class="banner-wrap">
        <div class="banner-item banner--item__1 banner--item__first">
            <div class="wrap www-rap">
                <picture>
                    <img width="1150" height="630"
                              srcset="//i00.eu/img/999997/1150x630a/562ojxe8/2229.webp 1x,//i00.eu/img/999997/2300x1260/25nkjd5z/2229.webp 2x"
                              src="//i00.eu/img/999997/1150x630a/562ojxe8/2229.webp">
                </picture>
                <div class="banner-info">
                    <h2 class="banner-info__headline">První Slide</h2>
                    <div class="banner-info__description">Popisek....</div>
                    <a class="button banner-info__button" href="https://www.simplia.cz">CTA</a>
                </div>
            </div>
        </div>
        <div class="banner-item banner--item__2">
            <div class="wrap www-rap">
                <picture>
                    <img class="auto-lazyload" width="1150" height="630"
                              data-srcset="//i00.eu/img/999997/1150x630a/79l5pfe2/2234.webp 1x,//i00.eu/img/999997/2300x1260/acf5nmee/2234.webp 2x"
                              src="//i00.eu/img/999997/1150x630a/79l5pfe2/2234.webp"
                              data-src="//i00.eu/img/999997/1150x630a/79l5pfe2/2234.webp"
                              srcset="//i00.eu/img/999997/1150x630a/79l5pfe2/2234.webp 1x,//i00.eu/img/999997/2300x1260/acf5nmee/2234.webp 2x"
                              data-loaded="true">
                </picture>
                <div class="banner-info">
                    <h2 class="banner-info__headline">Druhý slide</h2>
                    <div class="banner-info__description">popis :)</div>
                    <a class="button banner-info__button">CTA</a>
                </div>
            </div>
        </div>
        <div class="banner-item banner--item__3 banner--item__last">
            <div class="wrap www-rap">
                <picture>
                    <img class="auto-lazyload" width="1150" height="599"
                              data-srcset="//i00.eu/img/999997/1150x630a/a7mwzmns/2237.webp 1x,//i00.eu/img/999997/2300x1260/b9whiv1f/2237.webp 2x"
                              src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1150 599'%3E%3C/svg%3E"
                              data-src="//i00.eu/img/999997/1150x630a/a7mwzmns/2237.webp">
                </picture>
                <div class="banner-info">
                    <h2 class="banner-info__headline">Třetí slide</h2>
                </div>
            </div>
        </div>
    </div>
</div>
```

Nesting banner classes.

```twig
<i:banners source="repository.banner.findBy({sectionCode: 'testovaci'})" wrap="div.inner-wrap-class" banner-item-class="custom-item-class" banner-wrap-class="extra-banner-wrap">
    <source format="1150x630" src="desktop"/>
</i:banners>
```

```html
<div class="banner">
    <div class="banner-wrap extra-banner-wrap">
        <div class="banner-item banner--item__1 banner--item__first banner--item__last custom-item-class">
            <div class="inner-wrap-class">
                <picture>
                    <img width="1150" height="630"
                         srcset="//i00.eu/img/999997/1150x630a/562ojxe8/2229.webp 1x,//i00.eu/img/999997/2300x1260/25nkjd5z/2229.webp 2x"
                         src="//i00.eu/img/999997/1150x630a/562ojxe8/2229.webp">
                </picture>
            </div>
        </div>
    </div>
</div>
```

Banner title tooltip.

```twig
<i:banners source="repository.banner.findBy({sectionCode: 'testovaci'})">
    <source format="1150x630" src="desktop"/>

    <h2 data-role="title" tooltip></h2>
    <span data-role="cta"></span>
</i:banners>
```

```html
<div class="banner">
    <div class="banner-wrap">
        <div class="banner-item banner--item__1 banner--item__first banner--item__last">
            <picture>
                <img width="1150" height="630"
                          srcset="//i00.eu/img/999997/1150x630a/562ojxe8/2229.webp 1x,//i00.eu/img/999997/2300x1260/25nkjd5z/2229.webp 2x"
                          src="//i00.eu/img/999997/1150x630a/562ojxe8/2229.webp">
            </picture>
            <div class="banner-info">
                <h2 class="banner-info__headline">
                    První Slide
                    <span class="banner-info__headline-tooltip-text">Popisek....</span>
                </h2>
                <a class="button banner-info__button" href="https://www.simplia.cz">CTA</a>
            </div>
        </div>
    </div>
</div>
```

**Banner Parameters**

| Parameter | Required | Description |
|---|---|---|
| source | *yes* | `repository.banner.findBy()` |
| priority | *no* | allowed values: `high` / `low` (*default: high*). **low** -- lazyload on all images; **high** -- respects `visible-slides` |
| visible-slides | *no* | number of banners without lazyload (*default: 1*) |
| wrap | *no* | inner banner wrapper |
| class | *no* | add a custom class |
| banner-item-class | *no* | add a custom class to the banner items wrapper |
| banner-wrap-class | *no* | add a custom class to individual banner wrappers |
| picture-class | *no* | add a custom class to the picture wrapper |
| plugin | *no* | add helper classes for a specific plugin, e.g. `swiper` |
| click | *no* | configure banner click behavior. Allowed values: `banner` / `cta` / `off`. |
| quality | *no* | image compression quality for all sources. Allowed values: `low` / `normal` / `high` / `lossless`. If omitted, the shop default is used. |

**Banner Attributes**

| Attribute | Required | Description |
|---|---|---|
| arrows | *no* | show arrows for slide navigation |
| dots | *no* | show slide navigation dots |
| progress | *no* | show progress bar |
| thumbnails | *no* | show thumbnails with banner titles |
| transparent | *no* | image has transparency |
| fill | *no* | pad image with white borders |

**Banner source elements**

| data-role | Required | Attributes |
|---|---|---|
| desktop | *yes* | **format** -- required banner dimensions, **sizes** -- same as HTML5 sizes, required when multiple dimensions are specified (*default: 80vw*), **class** -- add a custom class, **quality** -- image compression quality (`low` / `normal` / `high` / `lossless`) overriding the banner-level quality for this source |
| tablet | *no* | **format** -- banner dimensions, **sizes** -- same as HTML5 sizes, required when multiple dimensions are specified, **media** -- same as HTML5 media, **class** -- add a custom class, **quality** -- image compression quality (`low` / `normal` / `high` / `lossless`) overriding the banner-level quality for this source |
| mobile | *no* | **format** -- banner dimensions, **sizes** -- same as HTML5 sizes, required when multiple dimensions are specified, **media** -- same as HTML5 media, **class** -- add a custom class, **quality** -- image compression quality (`low` / `normal` / `high` / `lossless`) overriding the banner-level quality for this source |

**Complete data-role list for banners**

| data-role | Required | Attributes |
|---|---|---|
| info-box | *no* | tag definition |
| title | *no* | tag definition |
| description | *no* | tag definition |
| cta | *no* | tag definition |

```twig
<i:banners source="repository.banner.findBy({sectionCode: 'testovaci'})" plugin="swiper" class="custom-class,super-class" click="banner" arrows dots progress>
    <source format="1150x630" src="desktop"/>
    <source media="(min-width: 440px) and (max-width: 768px)" format="748x486,249x162" sizes="100vw" src="tablet"/>
    <source media="max-width: 440px" format="640x790,320x340" sizes="100vw" src="mobile"/>

    <div data-role="info-box" class="infobox-extra-class" ></div>
    <h2 data-role="title"></h2>
    <div data-role="description"></div>
    <span data-role="cta"></span>
</i:banners>
```

```html
<!-- generated output -- subject to change! -->

<div class="banner custom-class super-class swiper-container">
    <div class="banner-wrap swiper-wrapper">
        <div class="banner-item banner--item__1 banner--item__first swiper-slide">
            <a href="https://www.simplia.cz">
                <picture>
                    <source srcset="//i00.eu/img/999997/640x790a/5e37hrnn/2227.webp 640w,//i00.eu/img/999997/320x340a/5072sf1e/2227.webp 320w"
                            media="max-width: 440px" sizes="100vw">
                    <source srcset="//i00.eu/img/999997/748x486a/cr5pv3u6/2228.webp 748w,//i00.eu/img/999997/249x162a/85hs2grx/2228.webp 249w"
                            media="(min-width: 440px) and (max-width: 768px)" sizes="100vw">
                    <img width="1150" height="630"
                         srcset="//i00.eu/img/999997/1150x630a/562ojxe8/2229.webp 1x,//i00.eu/img/999997/2300x1260/25nkjd5z/2229.webp 2x"
                         src="//i00.eu/img/999997/1150x630a/562ojxe8/2229.webp">
                </picture>
                <div class="banner-info infobox-extra-class">
                    <h2 class="banner-info__headline">První Slide</h2>
                    <div class="banner-info__description">Popisek....</div>
                    <span class="button banner-info__button">CTA</span>
                </div>
                <div class="banner-progress">
                    <div class="progress"></div>
                </div>
            </a>
        </div>
        <div class="banner-item banner--item__2 banner--item__last swiper-slide">
            <picture>
                <source srcset="//i00.eu/img/999997/640x790a/1ihskwis/2239.webp 640w,//i00.eu/img/999997/320x340a/4dkf8gy0/2239.webp 320w"
                        media="max-width: 440px" sizes="100vw">
                <source srcset="//i00.eu/img/999997/748x486a/697q3ssb/2238.webp 748w,//i00.eu/img/999997/249x162a/25bq8xs2/2238.webp 249w"
                        media="(min-width: 440px) and (max-width: 768px)" sizes="100vw">
                <img class="auto-lazyload swiper-lazy" width="1150" height="599"
                     data-srcset="//i00.eu/img/999997/1150x630a/a7mwzmns/2237.webp 1x,//i00.eu/img/999997/2300x1260/b9whiv1f/2237.webp 2x"
                     src="//i00.eu/img/999997/1150x630a/a7mwzmns/2237.webp"
                     data-src="//i00.eu/img/999997/1150x630a/a7mwzmns/2237.webp"
                     srcset="//i00.eu/img/999997/1150x630a/a7mwzmns/2237.webp 1x,//i00.eu/img/999997/2300x1260/b9whiv1f/2237.webp 2x"
                     data-loaded="true">
            </picture>
            <div class="banner-info infobox-extra-class">
                <h2 class="banner-info__headline">Druhý slide</h2>
            </div>
            <div class="banner-progress">
                <div class="progress"></div>
            </div>
        </div>
    </div>
    <div class="pagination swiper-pagination"></div>
    <div class="button-next swiper-button-next"></div>
    <div class="button-prev swiper-button-prev"></div>
</div>
```
