EchoBox

Public API

All of it is available. It is written down so that the milestones and the EchoEditor builder work to the same contract. Instance methods follow EchoEditor: on, destroy, and for the slider go, next, prev, current.

Loading

<link rel="stylesheet" href="/echobox/dist/echobox.min.css">
<script src="/echobox/dist/echobox.min.js" defer></script>

The classic script sets the globals. The ES module exports the same names and sets no global: import { EchoBox } from '/echobox/dist/echobox.esm.min.js'.

EchoBox

MemberStatusPurpose
EchoBox.versionavailableThe version
EchoBox.registerLanguage(code, entries)availableAdds a language, or adds to one. en and cs are in the bundle, the others will be separate files (D-012). The language comes from <html lang>, and English fills what a language lacks. The slider's keys are slider.carousel, slider.slide, slider.prev, slider.next, slider.pause, slider.play, slider.slides, slider.goTo, the lightbox's lightbox.dialog, lightbox.close, lightbox.prev, lightbox.next, lightbox.image, lightbox.item, lightbox.error, lightbox.zoom, lightbox.play, lightbox.pause, lightbox.fullscreen, lightbox.thumbs

EchoSlider

Available.

const slider = EchoSlider.create(el, {
  slidesToShow: 3,
  transition: 'push',    // the default, or 'fade', 'fade-push', 'circle', or an effect name
  from: 'right',         // 'right', 'left', 'bottom', 'top'
  fallback: 'fade-push', // for an effect, when GSAP is missing
  reveal: { h2: 'from-left', p: 'from-bottom' },
});
slider.next();
slider.prev();
slider.go(2);
slider.current;
const off = slider.on('change', ({ current, previous }) => {});
slider.destroy();

const all = EchoSlider.bind('[data-slider]', options);
all.destroy();
EchoSlider.registerTransition(name, ({ incoming, outgoing, sign, vertical, duration, ease, mode, animate, done }) => ({ cancel() {} }));

Each child of the element is a slide. Options keep Slick's names where they exist (D-008, D-023), and one Slick does not have here is ignored. The attribute data-slider holds the same options as JSON, and options in the call go over it. A second create on an element gives the same slider. go takes a whole number and ignores anything else. change comes once the move has started, so a listener may move the slider itself. Arrow keys with a modifier stay the browser's.

OptionDefaultPurpose
slidesToShow1How many are in view, a fraction such as 1.6 for a part of the next one. Above 1 always uses push
centerModefalseThe current slide stands in the middle, with parts of its neighbours on both sides when slidesToShow is a fraction above 1 (D-030)
arrows, dotstrue, falseThe controls. With no more slides than fit, there are none
infinitetrueThe loop. Without it the arrows say so with aria-disabled
speed500Milliseconds. 0 changes at once
ease'power2.out'As in EchoReveal
transition'push'push, fade, fade-push, circle (D-031), or an effect by name: parallax, wipe, curtain, zoom, stack, and in 3D and depth cube, door, dive (D-032). A name nobody knows gives a fade
fadefalsetrue means transition: 'fade'
from'right'Where the next slide comes from. Going back comes from the other side, and the keys follow
fallback'fade-push'What an effect becomes without GSAP
swipetrueDragging. See below
autoplay, autoplaySpeedfalse, 3000Moves by itself. With infinite: false it goes back to the first from the last. A slide whose video has data-len shows that many milliseconds instead. It waits while a modal dialog, such as the lightbox, is open
pauseOnHover, pauseOnFocustrue, trueWhat holds it. Only focus from the keyboard counts, not a click
useAutoplayToggleButtontrueThe button that stops it and the videos of the slides, which WCAG 2.2.2 needs
reveal{}Classes to add inside each slide, by selector
revealOptions{}For that content: distance (24), duration (600), delay (150), stagger (60), ease
regionLabelnullThe name of the region. Without it, or an aria-label or aria-labelledby of the site, it is "Slides"
appendArrows, appendDotsnullA selector or an element to put them in
responsive[][{ breakpoint: 900, settings: {} }]. Only the smallest breakpoint the window is under counts, the current slide stays, and a pause the visitor asked for stays
bodyClassfalseA class on <body> that names the slider and its slide, counted from 1: true takes the slider's id, as slider-home-slide-2, and a string is the name instead. A name that starts with slider-, as the builder's ids do, is not doubled: slider-hdfojg-slide-1 (D-033). See below
motion'auto'See Motion
animateby the classes, or 'auto'See Motion

A GSAP effect runs only when named (D-019). A site's own transition runs only with all motion: with animate: 'reduced' a fade plays instead (D-028). reveal adds reveal classes to what its selectors find inside each slide, and that content comes in when its slide becomes current, on GSAP when it is on the page and natively when it is not. .reveal and [data-reveal] already in a slide's HTML come in the same way. A fast swipe leaves nothing half way. A bind of EchoReveal leaves all of this to the slider, whichever of the two runs first.

One swipe moves at most one slide, however hard (D-020). A drag counts as a move from a fifth of a slide, or a shorter one at 0.4 pixels per millisecond. Only push follows the finger. During a move, input counts from the slide the move was heading for (D-022).

The arrow keys work while focus is inside the slider, except in a form field. Up and down on a vertical slider.

The page by the slide. With bodyClass, <body> has one class for each such slider, slider-<name>-slide-<n>, which changes as a move starts, before change. A breakpoint does not change the name. The page may write the first one itself, for the first paint, and destroy puts back the classes of <body> as they were; only if the page changed them meanwhile does it just remove its own. true on a slider without an id, or a name with a space, gives a warning and no class.

arrows: false with dots: false leaves only dragging for a pointer, which WCAG 2.5.7 does not allow on its own. A site that does this needs its own controls, through go, next and prev.

Videos. A <video> with autoplay in a slide plays only while its slide shows, the slider is in view and its autoplay is not stopped, by the button or, on animate: 'auto', by reduced motion (D-026, D-028). A slide that comes in plays its videos from the start. List the sources as CORE does, with the mp4 first, which every browser plays. destroy lets every video play, as its markup asks. A video the visitor starts is left alone.

Images. Write loading="lazy" in the HTML on all but the first, and the slider wakes what is about to show. A slide's own <img> or <video>, also inside a link or a <picture>, fills the slide with object-fit: cover: slides are as tall as the tallest, so photos of another shape or a taller video leave no gap, and a slider with a height of its own crops them all to it (D-029). A site keeps the image's own shape with a rule that names its slider, such as #gallery .slide > img { height: auto }. Before the script, [data-slider] is a row a visitor can scroll, with the widths of the slider: see the builder brief for several in view. For slidesToShow above 6, or in a slider without data-slider, set --per-view in the site's CSS. Spacing between slides goes inside the slide (D-021).

Centred, or a part of the next. Every slide is as wide as the others, 100% / slidesToShow. Only a slide that shows whole can be reached, and one that shows in part is inert until it is current. A centred move needs a spare slide beyond those that show at all, so with 1.6 in view it moves from 4 slides, and with fewer it changes at once. Slick's variableWidth is ignored: a site that used it with slides of one width sets the fraction they filled, such as slidesToShow: 1.6, and keeps its responsive. For the first paint, a fraction needs --per-view in the site's CSS, as the stylesheet reads only whole numbers from the attribute.

EchoLightbox

Available, with zoom, thumbnails, a slideshow and full screen (D-024, D-025), for images, videos, pages in a frame and content of the page (D-027).

const binding = EchoLightbox.bind('[data-lightbox], [data-fancybox]', { thumbs: true }); // the defaults
binding.destroy(); // also closes a lightbox it opened

const box = EchoLightbox.open([{ src, type, thumb, alt, caption }], { start: 0, thumbs: true }); // null with no items
box.current;
box.go(1);
box.close();
OptionDefaultPurpose
thumbstruefalse opens with the thumbnails hidden, as the eshop does. Their button shows them
animateby the classes, or 'auto'See Motion. Read when it opens: for bind from the classes of the link and around it, for open from those of <html>
start0open only: the item shown first
type of an itemsrcShows
image, the defaultthe imagethe image, which zooms
videoa video file, or the address of a video on YouTube or Vimeothe video with its controls, or the player in a frame
iframean http or https addressthe page in a frame
inline#id of an element of the pagethe element itself

bind opens the items of a group from a click on one of them, also on links added later (D-024). Links with the same value of data-lightbox or data-fancybox form a group in the order of the page, hidden ones included, and a link without a value opens alone. A link counts as fancyBox reads it (D-027): by data-type (image, video, iframe or inline), by an #id in data-src or href, or by the end of its path, from data-src before href. .avif, .bmp, .gif, .jpg, .jpeg, .png, .svg and .webp are images, .mp4, .m4v, .webm, .ogv and .mov videos, and .pdf a page in a frame. A link to a video on YouTube or Vimeo opens its player, YouTube's from youtube-nocookie.com, which the site's policy must allow in frame-src. Any other link, data-type="ajax" included, and a click with Shift, Ctrl, Alt or Meta, keeps its own way. A second lightbox closes the first. Links in a slider work the same, those in slides out of view included, and a drag that starts on one opens nothing (D-026).

EchoZoom

Available. The lightbox uses it for each image (D-025).

const zoom = EchoZoom.create(img); // its parent is the frame
zoom.zoomed;         // zoomed in
zoom.zoomable;       // larger than its place
zoom.toggle();       // in at the middle of the frame, or out again
zoom.panBy(x, y);    // pixels, zoomed in, within the edges
zoom.growFrom(rect); // plays the image growing from a box of the page, such as its thumbnail
zoom.reset();
zoom.destroy();

It zooms an image, as far as the image's own size, so one no larger than its place has nothing to zoom. The parent of the image is the frame: it should clip what overflows, and the image's edges never come inside it. A click or a tap zooms in at its point and out again, the wheel and a pinch zoom freely, and zoomed in a drag pans. The image moves by its own scale and translate, so a site should not set those on it. The keys are the caller's: the lightbox pans with the arrows through panBy. EchoZoom.create(img, { animate }) takes the setting of Motion, and with 'reduced' it jumps, as a zoom has nothing to fade. changed in the options is called when zoomed or zoomable may have changed, for the site's own zoom button; read both once after create too, as an image already loaded says nothing until the pointer comes to it. On a page, a touch on the image that is not a pinch belongs to the page: give the image touch-action: pan-y, and none while it has the class ebx-zoomed, as the demo does.

EchoReveal

Available.

const reveal = EchoReveal.bind();
const reveal = EchoReveal.bind({ '.card > h2': 'from-left', '.card > p': 'from-bottom' }, { once: true });
reveal.destroy();

Call it when the document is parsed: in a defer script, or from DOMContentLoaded.

The existing markup works as it is: .reveal with .from-left, .from-right, .from-top or .from-bottom, and [data-reveal]. [data-reveal="photo"] opens from a clip while its img settles from a slight scale. [data-reveal="row"] is the same as [data-reveal]. Without a side, an element comes from below, or from above when it enters over the top edge.

The first argument adds classes by selector, reveal always among them, and destroy() removes what it added. Rules run before anything else, so a rule's classes decide the direction. Inside an EchoSlider its reveal option does this instead, because a bind takes its trigger from the viewport (D-019).

OptionDefaultPurpose
distance8Pixels an element travels
duration600Milliseconds. A photo takes 4/3 of it, and its image twice. 0 shows an element at once
ease'power2.out''power2.out', 'expo.out' or any CSS easing run natively. Any other GSAP ease needs GSAP on the page, and becomes power2.out without it
stagger60Milliseconds between elements that come in together
oncetruefalse hides an element again when it leaves the viewport, and plays it again when it returns
motion'auto'See Motion
animateby the classes, or 'auto'See Motion. Each element's own, read when it binds

The hidden state. The stylesheet hides .reveal and [data-reveal] from the first paint, where the nearest class of Motion lets them move, and without a class unless the system asks for less motion. Without a script and in print nothing is hidden. An animate given only to bind does not reach the stylesheet, so give it as a class in the HTML. If nothing binds, a failsafe shows them after 4 seconds, and a script that arrives later plays the entrance over what is already visible.

EchoCounter

Available.

<b data-count="18900" data-suffix=" Kč">18 900 Kč</b>
<b data-count="3.4" data-dec="1" data-suffix=" %">3,4 %</b>
const counter = EchoCounter.bind({ duration: 2000 });
counter.destroy();

It counts when the element comes into view, and ends on the text of the HTML. data-dec sets the decimals, from 0 to 20: anything else is an error in the console, and also stops the counters that came into view with it. data-suffix follows the number, with its first space made unbreakable. Values on the way are formatted in the language of <html lang>. A number between 1000 and 2100 without decimals or a suffix reads as a year: it starts 40 lower and is not grouped. Without a script, or where nothing may move (see Motion), the text stays. An element without a text gets the formatted number. An element with child elements, or whose data-count is not a number, is left alone. Options: duration, motion, animate.

Motion

How much moves is animate, alike for all five components (D-028).

animateMovesMeant for
'auto'Everything, or nothing when the visitor's system asks for less motion (on Windows, Animation effects turned off)Institutions. The default
'off'Nothing, whatever the system allows
'reduced'Fades only, whatever the system asks: nothing travels, grows or is clippedE-shops
'always'Everything, whatever the system asksPresentation sites

A page sets it with a class on <html>, a part of the page or one component with a class on its element or around it, and a script with the option animate, also in data-slider:

<html class="ebx-animate-reduced">
<div id="slider-home" class="slider-fullscreen ebx-animate-always" data-slider>

The option wins, then the nearest class, and without either it is 'auto'. With 'reduced' a push puts the slide in place at once and fades it in, an effect, fade-push or circle becomes a fade, the content of a slide and a reveal only fade in, the lightbox fades its background and its images, and a zoom jumps. The autoplay and the videos of a slider run with 'reduced' and 'always' under reduced motion too, and the stop button stays as useAutoplayToggleButton says: without it, WCAG 2.2.2 is the site's to meet. The counter counts with both. A slider reads the classes at each move, the lightbox when it opens, a reveal when it binds, and a counter when its element comes into view.

Which engine runs it is motion: 'auto' | 'gsap' | 'native', see D-002 and architecture.md. 'gsap' on a page without GSAP runs natively. animate: 'off' replaces the former motion: 'none'.