Skip to main content

How to customize the widget appearance with CSS

Colors, position corner, titles, and messages are set in the eChat backend - see Widget settings. Everything else about how the widget sits on the page - the distance from the screen edge, the size of the chat window, its stacking order against your own fixed elements - is done with CSS in your Magento theme.

What your theme CSS can and cannot reach

The Magento extension injects only a small loader script. The widget itself is rendered by eChat as two <iframe> elements in your store page, and its stylesheet is injected as a <style data-echat-styles> tag into your page's <head>:

ElementWhat it is
#echat-buttonThe launcher button.
#echat-contentThe chat window.

Both are ordinary elements in your storefront DOM, so your theme's CSS can position, resize, and re-layer them like any other element.

What your CSS cannot reach is the content inside those iframes - the message list, the header, the input field. An iframe is a separate document, and no store stylesheet applies across that boundary. Those parts are styled through the backend settings (Primary Color, Title, Subtitle, and so on).

note

Use !important, or a more specific selector, on every override. The widget's <style data-echat-styles> tag is appended to <head> when the script loads - that is, after your theme's stylesheets - so a rule with the same specificity as the widget's own would lose the tie on source order.

Selectors

These selectors are stable and safe to target:

SelectorMatches
#echat-buttonThe launcher button iframe.
#echat-contentThe chat window iframe.
.echat-iframeBoth of them.
.echat-iframe--buttonThe launcher button iframe.
.echat-iframe--contentThe chat window iframe.

The widget also reflects its current state in attributes on those elements, so you can style a specific state instead of all of them:

AttributeOnMeaning
[data-position="BOTTOM_RIGHT"] / [data-position="BOTTOM_LEFT"]bothThe corner chosen in the backend. The button and the window carry their own Position setting, so they can differ.
[data-mode="mobile"] / [data-mode="desktop"]bothWhich layout the widget is using.
[data-has-title]buttonThe launcher has a Title, so it is a wide pill rather than a circle.
[data-launcher]buttonThe launcher is the visible entry point. On mobile the button is hidden without this attribute.
[data-open]windowThe chat window is open.
[data-visible]windowThe chat window occupies space. Without it the window is collapsed to 1px, so size overrides must target [data-visible].
[data-expanded]windowThe visitor expanded the window to its larger size.
[data-popover]windowThe window is showing a popover, for example the invitation message.

Defaults you are overriding

Knowing the built-in values makes the overrides predictable:

Launcher buttonChat window
Distance from the bottom070px - it sits directly above the button
Distance from the anchored side00
Size70x70, or 200px wide with a Title1px when collapsed, 420x700 when visible, 520px / 95vh when expanded
z-index21474836412147483640

On a mobile viewport the open window covers the whole screen and ignores these values.

Where to put the CSS

Add the rules to your theme's stylesheet - for a Luma-based theme, app/design/frontend/<Vendor>/<theme>/web/css/source/_extend.less; for Hyvä, your Tailwind CSS entry file - then deploy static content and flush the cache.

Example: move the widget away from the corner

The most common case: a sticky footer, a cookie bar, or a back-to-top button already occupies the corner. Lift the widget 50px off the bottom and pull it 40px in from the right:

#echat-button {
bottom: 50px !important;
right: 40px !important;
}

/* The window sits 70px above the button, so its offset is 50 + 70. */
#echat-content:not([data-mode="mobile"]) {
bottom: 120px !important;
right: 40px !important;
}

Two things to note:

  • The 70px gap is what keeps the window and the button aligned as one stack. Whatever you set on the button, add 70px to it for the window.
  • The window rule is scoped with :not([data-mode="mobile"]) on purpose. Without it, an !important offset would also apply on mobile and break the full-screen chat window there. The launcher button keeps its offset on mobile either way.

With Position set to Bottom Left, use left instead of right:

#echat-button {
bottom: 50px !important;
left: 40px !important;
}

#echat-content:not([data-mode="mobile"]) {
bottom: 120px !important;
left: 40px !important;
}

Example: make the chat window wider

Size lives on the visible state, so target [data-visible]:

#echat-content[data-visible] {
width: 480px !important;
max-height: 760px !important;
}

Leave [data-expanded] alone unless you also want to change the expanded size:

#echat-content[data-visible][data-expanded] {
width: 600px !important;
}

Example: keep the widget below your own fixed element

The widget uses a very high z-index. If one of your own fixed elements - a cookie bar, a slide-out cart - must stay above it, lower the widget instead of raising yours:

.echat-iframe {
z-index: 2000 !important;
}

Keep the value above the rest of your storefront, or the chat window will end up behind page content.

Example: hide the widget on mobile

#echat-button[data-mode="mobile"],
#echat-content[data-mode="mobile"] {
display: none !important;
}
note

The widget script is served from the eChat CDN and cached, and your storefront pages are cached by Magento as well. After a change, flush the Magento cache and reload with a hard refresh; a short delay before the new styles appear is normal.

warning

The selectors and state attributes above are stable. The default sizes and offsets in the table are not a contract - they can change in a widget update. Keep your overrides to the properties you actually need, so an update changes as little as possible for you.