Controllers
Bind platform behavior to the markup you write with data-cartisto.
Controllers are the preferred way to add behavior. You write the HTML with your own classes and layout; the platform binds behavior to a marker. You keep the look; the platform owns the logic.
The grammar
data-cartisto="<name>"— the root marker. The platform’s controller for<name>runs once per marked element.data-cartisto-ref="<part>"— names a child the controller needs.data-cartisto-bound— written by the platform after binding. Never author it.
<form data-cartisto="newsletter-form">
<input type="email" data-cartisto-ref="email" required />
<button type="submit">{{ 'ui.subscribe' | t }}</button>
</form>
That’s the whole edit. The platform’s newsletter controller finds the form,
reads the email ref, calls cartisto.newsletter.subscribe(...), and handles
success/error toasts — identically in every theme.
Controllers the platform ships
| Marker | Enhances |
|---|---|
data-cartisto="newsletter-form" |
Newsletter signup form |
data-cartisto="products-listing" |
The collection/search grid — facets, sorting, pagination |
| PDP form, variant picker, gallery | Product page interactions |
The listing controller reads config from data attributes on the marked element
(e.g. data-lang-prefix, data-initial-category-id) so its look stays yours.
The registry API
If you write your own presentation controller in main.js, register it the same
way the platform does:
cartisto.ui.register("promo-timer", function (root) {
const label = cartisto.ui.ref(root, "label");
// …bind behavior, read cartisto.state, call cartisto.* …
});
// After a client-side re-render, bind any new markers:
cartisto.ui.scan(container);
register(name, factory)—factory(root)runs once per matching element.scan(root = document)— bind not-yet-bound markers (safe to call repeatedly; binding is idempotent via thedata-cartisto-boundstamp).ref(root, part)— shorthand for the child lookup.
Presentation JS is allowed
Controllers you write for presentation (a carousel, an accordion, a sticky
header) are fine and expected in main.js. The line is: no fetch, no
commerce rules — call cartisto.* for anything that talks to the store.