Manual: EchoBox on a site
How to put EchoBox on a page, and how to move a site from Slick and fancyBox. What each option does is in the API reference, and why it works so in doc/decisions.md of the repository.
1. Load it
One stylesheet and one script, both from dist/ (npm run build). For EchoEngine they belong in CORE next to the libraries they replace, such as core/assets/echobox/.
<link rel="stylesheet" href="/assets/echobox/echobox.min.css">
<script src="/assets/gsap/gsap.min.js" defer></script> <!-- optional: only the named effects need it -->
<script src="/assets/echobox/echobox.min.js" defer></script>
<script src="/js/site.js" defer></script>
defer keeps the order, so site.js finds the globals EchoBox, EchoSlider, EchoLightbox, EchoZoom, EchoReveal and EchoCounter. GSAP, when the page has it, goes before EchoBox. A page of ES modules imports the same names from echobox.esm.min.js instead.
2. Start it
All in one place of site.js, once the document is parsed:
EchoReveal.bind(); // .reveal and [data-reveal]
EchoCounter.bind(); // [data-count]
EchoSlider.bind(); // every [data-slider], as the EchoEditor writes it
EchoSlider.create(document.getElementById('slider-home'), { autoplay: true, autoplaySpeed: 5000, fade: true });
EchoLightbox.bind(); // [data-lightbox] and [data-fancybox]
Each call returns an object with destroy(), which puts the markup back as it was. Content loaded later needs another bind, except for the lightbox, which also opens links added later.
3. From Slick
The options keep Slick's names (D-008, D-023), and one it does not know is ignored, so a call usually moves over as it is:
// before
$('#slider-home').slick({ autoplay: true, autoplaySpeed: 5000, fade: true, dots: true });
// after
EchoSlider.create(document.getElementById('slider-home'), { autoplay: true, autoplaySpeed: 5000, fade: true, dots: true });
A jQuery set with several sliders, such as $('.slider.gallery'), becomes EchoSlider.bind('.slider.gallery', {...}).
| Slick | EchoSlider |
|---|---|
slidesToShow, arrows, dots, autoplay, autoplaySpeed, infinite, pauseOnHover, pauseOnFocus, useAutoplayToggleButton, speed, swipe, fade, regionLabel, appendArrows, appendDots, responsive, centerMode | The same |
easing | ease, which also takes GSAP's names |
variableWidth with slides of one width | A fraction of slidesToShow, such as 1.6, with centerMode as before (D-030) |
variableWidth with slides of different widths | Not supported: keep Slick on that slider |
slidesToScroll, adaptiveHeight, zIndex, touchMove | Ignored: one slide per move, slides as tall as the tallest |
$(el).slick('slickGoTo', n) | slider.go(n), and next(), prev(), current |
on('afterChange'), on('beforeChange') | slider.on('change', ({ current, previous }) => ...), which comes once the move has started |
$(el).slick('unslick') | slider.destroy() |
Then check:
- Breakpoints count as in Slick: the smallest one the window is under wins.
- Spacing between slides goes inside the slide, as padding, not as a margin on it (D-021).
- Images in a slide fill it with
object-fit: cover(D-029). Writewidthandheighton each<img>, andloading="lazy"on all but the first. - The first paint. Before the script a
[data-slider]is a row that scrolls, with the widths ofslidesToShowfrom 2 to 6 read from the attribute. A slider made bycreate, or a fraction, needs--per-viewin the site's CSS to have the right width from the first paint. - Slick's styles (
.slick-*) can go once no slider on the site uses Slick.
4. From fancyBox and Fancyapps
The markup stays: data-fancybox with a group name, data-caption, data-type, data-src, and a href to the large image (D-024, D-027). Only the call changes:
// fancyBox 3 // Fancyapps 5
$('a.lb').fancybox({ ... }); Fancybox.bind('[data-fancybox]', { ... });
// both become
EchoLightbox.bind();
A link that the site opened by its class alone, without data-fancybox, gets data-lightbox or data-fancybox, or the site passes its selector: EchoLightbox.bind('a.lb'). Fancyapps' options (Thumbs, Toolbar and the rest) are not read: the thumbnails, zoom, slideshow and full screen are always there, and thumbs: false starts with the thumbnails hidden.
A link to YouTube or Vimeo opens its player in a frame, so the site's policy allows them: frame-src https://www.youtube-nocookie.com https://player.vimeo.com.
5. The look of the controls
The controls are buttons with these classes, and their rules weigh nothing (:where), so any rule of the site wins:
| Class | What |
|---|---|
.ebx-control | Every control of a slider |
.ebx-prev, .ebx-next, .ebx-pause | The arrows and the autoplay's button, each with an SVG icon in currentColor |
.ebx-dots, .ebx-dot, .ebx-dot[aria-current] | The dots, the dot drawn by ::before |
.ebx-lightbox, .ebx-lightbox-bar, .ebx-lightbox-thumb | The lightbox, its toolbar and its thumbnails |
#slider-home .ebx-next { background: var(--brand); border-color: transparent; }
#slider-home .ebx-dot::before { background: transparent; border-color: var(--brand); }
#slider-home .ebx-dot[aria-current]::before { background: var(--brand); }
appendArrows and appendDots put the controls into an element of the site, as in Slick. Keep a button at least 24 by 24 pixels (WCAG 2.5.8): the defaults are 44 for an arrow and 24 for a dot. A slider keeps the z-index of its slides and controls inside it, so a sticky header with any z-index above 0 stays over it.
The page by the slide. With bodyClass: true, a slider keeps a class on <body> that names it by its id and its slide, counted from 1, such as slider-home-slide-2. A string names it instead: bodyClass: 'hero' gives slider-hero-slide-1. The EchoEditor builder's id slider-hdfojg gives slider-hdfojg-slide-1, not slider-slider-.... It works in data-slider too, and changes as the move starts, so the rest of the page can follow the slide:
.slider-home-slide-2 .site-header { color: #fff; }
For the first paint, write the first class on <body> in the HTML yourself.
6. Motion
By default everything moves as the visitor's system asks: nothing travels for someone who asked for less motion. A site that wants otherwise puts a class on <html> or on any element around a component: ebx-animate-off, ebx-animate-reduced (fades only) or ebx-animate-always, or passes animate to one component (D-028). Details in the API reference.
7. Languages
The labels of the buttons follow <html lang>: English and Czech are in the bundle, and English fills what a language lacks. Another language is added before the components start:
EchoBox.registerLanguage('de', { 'slider.next': 'Nächstes Bild', 'slider.prev': 'Vorheriges Bild' });
The keys are listed in the API reference.
8. The policy
EchoBox runs under a strict Content-Security-Policy: no inline script, no eval, no style attribute in its markup, styles set through the CSSOM only. A site needs nothing for it beyond script-src and style-src for its own files, and frame-src for the players of section 4.
9. Checklist for moving a site
- Load EchoBox, and keep Slick and fancyBox loaded until every call is moved.
- Move each slider and each lightbox call, one at a time, and look at it on a wide and a narrow window.
- Restyle the controls (section 5), and remove the site's
.slick-*and.fancybox-*rules. - Write
width,heightandloading="lazy"on the images of sliders and galleries. - Remove Slick, fancyBox and, where nothing else needs it, jQuery.
- Open the browser's console: no errors and no policy violations. Try the keyboard (Tab, the arrow keys, Escape) and a phone.