Envie
Guides

Theming & parts reference

Style every Envie component from your own CSS — parts, state attributes, custom properties, and the styling contract behind them.

This page is the complete styling surface of the Envie components: what you can target, and the rules that keep it stable.

The contract

The components ship no styles beyond :host { display: inline-block }. No theme, no reset, no opinion. Styling always comes from outside — your theme CSS, your app's stylesheet — through three stable surfaces:

  1. Parts — internal elements exposed via ::part().
  2. State attributes — reflected on the host, so plain attribute selectors work.
  3. Custom properties — a handful of tokens, all inheriting by default.

These are covered by the same stability promise as the API: they never change meaning within a major version.

Parts

ComponentPartWhat it is
<envie-button>buttonThe real <button> element
<envie-button>labelText wrapper inside the button
<envie-badge>badgeThe count wrapper
<envie-share>button, labelSame shape as the save button
envie-button::part(button) {
	border: 1px solid currentColor;
	border-radius: 999px;
	padding: 0.5rem 1rem;
	background: transparent;
	cursor: pointer;
}

State attributes

Reflected on the host element — no JavaScript needed to react to them:

AttributeOnMeaning
savedenvie-buttonThe product is in the wishlist
busyenvie-button, envie-shareA request is in flight
disabledenvie-buttonInteraction disabled
countenvie-badgeCurrent item count (stringified)
emptyenvie-listNothing to show
loadingenvie-listFirst render not yet complete
hiddenenvie-shareSharing unavailable for this shop or list
envie-button[saved]::part(button) {
	background: currentColor;
}
envie-button[busy] {
	opacity: 0.6;
	pointer-events: none;
}
envie-badge[count="0"] {
	display: none;
}

Custom properties

TokenPurpose
--envie-icon-sizeIcon dimensions
--envie-colorResting color
--envie-color-activeSaved-state color
--envie-transitionState-change transition

All default to inherited/neutral values, so an unstyled component picks up your typography and colors instead of fighting them.

Wishlist items are your markup

<envie-list> renders items into light DOM — your theme CSS applies to them directly, no parts needed. You control the item markup two ways:

A theme section (Liquid stores) — set card-section to one of your theme's section filenames and every saved product renders through your theme's own product-card section:

<envie-list card-section="product-card"></envie-list>

A template (full control) — provide the item markup yourself; elements carrying data-envie-* attributes are filled per item:

<envie-list>
	<template slot="item">
		<div class="my-card">
			<a data-envie-link><img data-envie-image alt="" /></a>
			<p data-envie-title></p>
			<envie-button data-envie-toggle></envie-button>
		</div>
	</template>
</envie-list>
AttributeFilled with
data-envie-linkhref to the product page
data-envie-imageProduct image src
data-envie-titleProduct title text
data-envie-toggleWired as this item's save button

A product that no longer resolves gets data-envie-unavailable on the card's root instead of vanishing — style it as you see fit.

When both are present, the section wins; a product the section can't render falls back to the template rather than blanking the list.

Liquid theme blocks and .envie-styled

The theme app blocks (Wishlist button, badge, page) default to Use Envie's appearance — a small stylesheet owned by the app embed, applied only to elements carrying the envie-styled class. Turn the toggle off and the block renders the bare element for your CSS.

A hand-written tag never gets that class, so the appearance settings never fight your stylesheet. Rule of thumb: blocks look finished for merchants; tags are raw for developers.

A starting point

@getenvie/components/starter.css is an optional, documented stylesheet with sensible defaults for all four components — import it, copy from it, or ignore it:

@import "@getenvie/components/starter.css";

Common mistakes

  • Styling the host instead of the part. envie-button { background: … } paints the host box, not the button. Use envie-button::part(button).
  • Expecting styles to cross the shadow boundary. Only parts, attributes, and custom properties do. That's the point: your CSS can never break our internals, and ours doesn't exist.
  • Not sizing the button box. Give the host fixed dimensions in your CSS (the theme blocks already do) so layout doesn't shift when the element upgrades.

On this page