Styling Weavy components
Adjusting theme colors and general styling is done with pure CSS using custom properties — no preprocessor required.
To set a property, simply add it to your stylesheet using a :root block. Here’s an example that changes the primary theme color.
:root {
--wy-theme-color: red;
}
You can also target individual components or a subset of components with a specific class.
wy-messenger {
--wy-theme-color: green;
}
wy-messenger.your-class {
--wy-theme-color: blue;
}
Alternatively, you can set properties inline directly on an element.
<wy-messenger style="--wy-theme-color: blue"></wy-messenger>
Properties
Weavy makes use of the following property values to provide a consistent appearance across components.
Note that, because they live at the :root level, they’re prefixed with --wy- to avoid collisions with other libraries.
:root {
/* Theme colors */
--wy-theme-color: unset;
--wy-color-scheme: unset; /* normal | light | dark */
/* Size */
--wy-size: 1rem; /* Base size for layout */
/* Padding */
--wy-padding: .5rem;
--wy-padding-sm: calc(.5 * var(--wy-padding, .5rem)); /* .25rem */
--wy-padding-lg: calc(1.5 * var(--wy-padding, .5rem)); /* .75rem */
--wy-padding-outer: var(--wy-padding, 0);
/* Gap */
--wy-gap: .5rem;
--wy-gap-sm: calc(.5 * var(--wy-gap, .5rem)); /* .25rem */
--wy-gap-lg: calc(1.5 * var(--wy-gap, .5rem)); /* .75rem */
--wy-gap-xl: calc(2 * var(--wy-gap, .5rem)); /* 1rem */
/* Border */
--wy-border: 1px;
--wy-border-outline: 0;
--wy-border-radius: .5rem;
--wy-border-radius-sm: calc(var(--wy-border-radius, .5rem) - .25 * var(--wy-padding, .5rem)); /* .375rem */
--wy-border-radius-lg: var(--wy-border-radius, 1.25rem);
--wy-border-radius-pill: var(--wy-border-radius, 2.5rem);
--wy-border-radius-outer: var(--wy-border-radius, .5rem);
/* Typography */
--wy-font-family: unset;
--wy-font-monospace: "ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace";
--wy-font-size: var(--wy-size, 1em); /* Assumes the inherited font-size, typically 16px */
--wy-font-weight: unset;
--wy-font-weight-bold: 600;
--wy-line-height: 1.5;
--wy-font-size-xxs: calc(.625 * var(--wy-font-size, 1em)); /* .625em 10px */
--wy-font-size-xs: calc(.75 * var(--wy-font-size, 1em)); /* .75em 12px */
--wy-font-size-sm: calc(.875 * var(--wy-font-size, 1em)); /* .875em 14px */
--wy-font-size-lg: calc(1.125 * var(--wy-font-size, 1em)); /* 1.125em 18px */
--wy-font-size-xl: calc(1.25 * var(--wy-font-size, 1em)); /* 1.25em 20px */
--wy-font-size-xxl: calc(1.5 * var(--wy-font-size, 1em)); /* 1.5em 24px */
--wy-headings-font-size: var(--wy-font-size, 1em);
--wy-headings-font-style: unset;
--wy-headings-font-family: var(--wy-font-family, unset);
--wy-headings-font-weight: var(--wy-font-weight-bold, 600);
--wy-headings-line-height: var(--wy-line-height, 1.5);
--wy-h1-font-size: var(--wy-font-size-xxl, 1.5em);
--wy-h1-font-weight: var(--wy-headings-font-weight, var(--wy-font-weight-bold, 600));
--wy-h1-margin: 0 0 var(--wy-gap, .5rem);
--wy-h2-font-size: var(--wy-font-size-xl, 1.25em);
--wy-h2-font-weight: var(--wy-headings-font-weight, var(--wy-font-weight-bold, 600));
--wy-h2-margin: var(--wy-gap-xl, calc(2 * var(--wy-gap, .5rem))) 0 var(--wy-gap-sm, calc(.5 * var(--wy-gap, .5rem)));
--wy-h3-font-size: var(--wy-font-size-lg, 1.125em);
--wy-h3-font-weight: var(--wy-headings-font-weight, var(--wy-font-weight-bold, 600));
--wy-h3-margin: var(--wy-gap-xl, calc(2 * var(--wy-gap, .5rem))) 0 var(--wy-gap-sm, calc(.5 * var(--wy-gap, .5rem)));
--wy-h4-font-size: var(--wy-font-size, 1em);
--wy-h4-font-weight: var(--wy-headings-font-weight, var(--wy-font-weight-bold, 600));
--wy-h4-margin: var(--wy-gap-xl, calc(2 * var(--wy-gap, .5rem))) 0 0;
--wy-h5-font-size: var(--wy-font-size, 1em);
--wy-h5-font-weight: var(--wy-headings-font-weight, var(--wy-font-weight-bold, 600));
--wy-h5-margin: 0;
--wy-h6-font-size: var(--wy-font-size, 1em);
--wy-h6-font-weight: inherit;
--wy-h6-margin: 0;
/* Documents */
--wy-document-headings-font-family: var(--wy-headings-font-family, var(--wy-font-family, unset));
--wy-document-headings-line-height: var(--wy-headings-line-height, var(--wy-line-height, 1.5));
--wy-document-h1-font-size: calc(2 * var(--wy-font-size, 1em)); /* 2em 32px */
--wy-document-h1-font-weight: var(--wy-font-weight-bold, 600);
--wy-document-h1-margin: 0 0 var(--wy-gap, .5rem);
--wy-document-h2-font-size: calc(1.5 * var(--wy-font-size, 1em)); /* 1.5em 24px */
--wy-document-h2-font-weight: var(--wy-font-weight-bold, 600);
--wy-document-h2-margin: var(--wy-gap-xl, calc(2 * var(--wy-gap, .5rem))) 0 var(--wy-gap-sm, calc(.5 * var(--wy-gap, .5rem)));
--wy-document-h3-font-size: calc(1.25 * var(--wy-font-size, 1em)); /* 1.25em 20px */
--wy-document-h3-font-weight: var(--wy-font-weight-bold, 600);
--wy-document-h3-margin: var(--wy-gap-xl, calc(2 * var(--wy-gap, .5rem))) 0 var(--wy-gap-sm, calc(.5 * var(--wy-gap, .5rem)));
--wy-document-h4-font-size: calc(1.125 * var(--wy-font-size, 1em)); /* 1.125em 18px */
--wy-document-h4-font-weight: var(--wy-font-weight-bold, 600);
--wy-document-h4-margin: var(--wy-gap-xl, calc(2 * var(--wy-gap, .5rem))) 0 0;
--wy-document-h5-font-size: var(--wy-font-size, 1em); /* 1em 16px */
--wy-document-h5-font-weight: var(--wy-font-weight-bold, 600);
--wy-document-h5-margin: var(--wy-gap-xl, calc(2 * var(--wy-gap, .5rem))) 0 0;
--wy-document-h6-font-size: var(--wy-font-size, 1em); /* 1em 16px */
--wy-document-h6-font-weight: var(--wy-font-weight-bold, 600);
--wy-document-h6-margin: 0;
/* Links */
--wy-link-decoration: none;
--wy-link-hover-decoration: var(--wy-link-decoration, none);
/* Tables */
--wy-table-cell-padding-x: var(--wy-gap-sm, calc(.5 * var(--wy-gap, .5rem)));
--wy-table-cell-padding-y: var(--wy-gap-sm, calc(.5 * var(--wy-gap, .5rem)));
/* Transitions */
--wy-transition-reveal-delay: 1s;
/* Opacity */
--wy-opacity-backdrop: 95%;
--wy-opacity-muted: 65%;
--wy-opacity-disabled: 38%;
/* State layer */
--wy-opacity-state-hover: 8%;
--wy-opacity-state-focus: 12%;
--wy-opacity-state-active: 12%;
--wy-opacity-state-drag: 16%;
/* Components */
--wy-titlebar-height: calc(max(1lh, var(--wy-button-size, 2.5rem)) + 2 * var(--wy-padding-sm, .25rem)); /* 3rem */
--wy-toolbar-height: calc(max(1lh, var(--wy-button-size, 2.5rem)) + 2 * var(--wy-padding-sm, .25rem)); /* 3rem */
--wy-footerbar-height: 4rem;
/* Buttons */
--wy-button-size: calc(var(--wy-button-line-height, 1.5) * 1rem + 2 * var(--wy-button-padding-y, var(--wy-padding, .5rem))); /* 2.5rem */
--wy-button-padding-x: calc(var(--wy-padding, .5rem) + 2 * var(--wy-button-padding-y, var(--wy-padding, .5rem))); /* 1.5rem */
--wy-button-padding-y: var(--wy-padding, .5rem);
--wy-button-gap: var(--wy-gap-sm, calc(.5 * var(--wy-gap, .5rem)));
--wy-button-font-family: var(--wy-font-family, unset);
--wy-button-font-size: var(--wy-font-size, 1em);
--wy-button-font-weight: var(--wy-font-weight, unset);
--wy-button-line-height: var(--wy-line-height, 1.5);
--wy-button-border-width: var(--wy-border-outline, 0);
--wy-button-border-color: transparent;
--wy-button-border-radius: var(--wy-border-radius, 1.25rem);
/* Inputs */
--wy-input-padding-y: var(--wy-padding, .5rem);
--wy-input-padding-x: var(--wy-padding-lg, calc(1.5 * var(--wy-padding, .5rem)));
--wy-input-font-family: var(--wy-font-family, inherit);
--wy-input-font-size: var(--wy-font-size, 1em);
--wy-input-font-weight: var(--wy-font-weight, unset);
--wy-input-line-height: calc(var(--wy-line-height, 1.5) * 1rem);
--wy-input-border-width: var(--wy-border, 1px);
--wy-input-border-radius: var(--wy-border-radius, .5rem);
--wy-input-filled-border-radius:var(--wy-border-radius-lg, var(--wy-border-radius, 1.25rem));
--wy-input-filled-border-width: var(--wy-border-outline, 0);
/* Dropdowns */
--wy-dropdown-padding-x: var(--wy-padding-lg, calc(1.5 * var(--wy-padding, .5rem)));
--wy-dropdown-padding-y: var(--wy-padding, .5rem);
--wy-dropdown-gap: var(--wy-gap, .5rem);
--wy-dropdown-border-radius: var(--wy-border-radius, .5rem);
--wy-dropdown-border-width: var(--wy-border, 1px);
/* Items */
--wy-item-title-font-size: var(--wy-font-size, 1em);
--wy-item-title-font-weight: var(--wy-font-weight, unset);
--wy-item-title-font-weight-bold: var(--wy-font-weight-bold, 600);
/* Avatars */
--wy-avatar-font-size: .382em; /* Golden section */
--wy-avatar-font-weight: var(--wy-font-weight-bold, unset);
--wy-avatar-border-radius: var(--wy-border-radius, 50%);
/* Messages */
--wy-message-padding: var(--wy-padding-lg, calc(1.5 * var(--wy-padding, .5rem)));
/* Max width for embeds and image attachments */
--wy-embed-content-max-size: 48rem;
--wy-image-max-size: 32rem;
}
Colors
The easiest way to quickly change the entire color theme is with the --wy-theme-color property. When specified, it automatically generates a complete color palette that applies to the specified components.
:root {
--wy-theme-color: red;
}
wy-messenger {
--wy-theme-color: #00ff00;
}
<wy-messenger style="--wy-theme-color: hsl(95deg, 38%, 62%);"></wy-messenger>
Another alternative is to add a <meta name="theme-color">
element to the <head of your page. When present, it is picked up by Weavy and used to generate a theme (meaning you don’t have to set the --wy-theme-color property as it is done automatically).
<head>
...
<meta name="theme-color" content="#00ff00" />
</head>
If you want more precise control of the color theme you can define all color tones in the palette instead of setting the single --wy-theme-color property. The colors shades are named from 0 to 100, similar (but not equal) to lightness of the HSL color model, where 0 is dark and 100 is light.
We recommend generating colors tones using Material Theme Builder to get matching color tones and proper dark mode out of the box. This will usually meet Web color contrast standards to get minimum contrast ratio of 3:1.
Dark mode
Weavy has built in support for dark mode. The dark theme is based on the color tokens recommended for Material Design dark theme. That means it will follow WCAG recommendations and use your defined colors.
To enable dark mode for a component you just have to set the wy-dark class or set the --wy-color-scheme: dark; CSS custom property.
Example: Dark mode on all components
<html class="wy-dark">
...
<body>
...
<wy-messenger></wy-messenger>
</body>
</html>
Example: Dark mode on a single component
<wy-messenger class="wy-dark"></wy-messenger>
Example: Dark mode using CSS variable
<style>
:root {
/* Set dark mode for all Weavy components */
--wy-color-scheme: dark;
/* Recommended: Set dark mode for the page and other components */
color-scheme: dark;
}
</style>
<wy-messenger></wy-messenger>
To get dark mode to follow the browser or system settings, you can toggle it using a media query script.
function setWeavyDarkMode(e) {
if (e.matches) {
document.documentElement.classList.add("wy-dark");
} else {
document.documentElement.classList.remove("wy-dark");
}
}
const colorScheme = matchMedia("(prefers-color-scheme: dark)");
// Listen to dark mode changes
colorScheme.addEventListener("change", setWeavyDarkMode);
// Set initial dark mode
setWeavyDarkMode(colorScheme);
Parts
Weavy components use a shadow DOM to encapsulate their styles and behaviors. As a result, you can’t simply target their internals with the usual CSS selectors.
Instead, components expose “parts” that can be targeted with the CSS part selector, or ::part(). Again, this is done with pure CSS — no preprocessor required.
Here’s an example that hides the "New conversation" button in the messenger component.
wy-messenger::part(wy-conversation-new) {
display: none;
}
Most (but not all) components expose parts. You can find them in each component’s documentation under the “CSS Parts” section.
Roundness
The border radius of corners can be set using --wy-border-radius. Note that this affects all rounded corners.
You can also set the outermost border radius on the components using --wy-border-radius-outer. This can be useful if you want to keep the roundness inside the components, but adapt the outer roundness to the container where you are placing it.
:root {
--wy-border-radius: 2px;
--wy-border-radius-outer: 0;
}
To specifically override the roundness of avatars it is also possible to set --wy-avatar-border-radius.
Sizing
Component sizing is based on the default 1rem root size of the page, typically 16px in the browser. You can override this with --wy-size to set the base size unit for components. Setting 2rem will double the scale of the components.
:root {
--wy-size: 2rem;
}
Spacing
Spacing properties are used to provide consistent spacing between content in your app. All paddings and gaps are derived from these properties, but might be bigger or smaller depending on where in the components they are used.
:root {
--wy-padding: 1rem;
--wy-gap: 12px;
--wy-padding-outer: 8px;
}
You can adjust the outermost padding to fit your container properly using the --wy-padding-outer.
Typography
The font family used in components is normally automatically inherited from the page, but can be customized by specifying a value for the --wy-font-family property.
:root {
--wy-font-family: monospace;
}
Font sizes use rem units so they scale with the base font size, which is the font-size in the root (usually the <html> node).
To override it you can set the --wy-font-size property.
:root {
--wy-font-size: 1.5rem;
}