-
Notifications
You must be signed in to change notification settings - Fork 6
docs: Update email layouts, MJML, and client previews documentation #1500
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
8b063f8
a630697
2e443e0
6d37706
5819a6a
b94b155
0cd955d
4088314
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -105,10 +105,16 @@ Inject account- and environment-level variables into your layout with the `vars. | |
|
|
||
| Branding properties set in account settings are available under `vars.branding.*`: | ||
|
|
||
| - `vars.branding.logo_url` | ||
| - `vars.branding.icon_url` | ||
| - `vars.branding.primary_color` | ||
| - `vars.branding.primary_color_contrast` | ||
| | Variable | Description | | ||
| | ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | ||
| | `vars.branding.logo_url` | URL of the logo image for your brand. | | ||
| | `vars.branding.icon_url` | URL of the icon image for your brand. | | ||
| | `vars.branding.dark_logo_url` | URL of the logo image for dark mode. Defaults to `logo_url` if not set. | | ||
| | `vars.branding.dark_icon_url` | URL of the icon image for dark mode. Defaults to `icon_url` if not set. | | ||
| | `vars.branding.primary_color` | Primary brand color (hex). Defaults to `#000000`. | | ||
| | `vars.branding.primary_color_contrast` | Contrast color for text on primary color backgrounds (hex). Defaults to `#FFFFFF`. | | ||
| | `vars.branding.dark_primary_color` | Primary brand color for dark mode (hex). Defaults to `primary_color` if not set. | | ||
| | `vars.branding.dark_primary_color_contrast` | Contrast color for text on dark mode primary color backgrounds (hex). Defaults to `primary_color_contrast` if not set. | | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With this change in control these default to |
||
|
|
||
| With [per-tenant branding](/multi-tenancy/per-tenant-branding), Knock resolves these properties against the `tenant_id` on the workflow run, falling back to account-level branding if the tenant has none set. | ||
|
|
||
|
|
@@ -223,6 +229,54 @@ The `<!--[if !mso]>` conditional prevents Outlook, which doesn't support `prefer | |
| } | ||
| /> | ||
|
|
||
| ### Styling buttons | ||
|
|
||
| The Knock default email layout automatically styles buttons using your branding colors, with full support for dark mode. | ||
|
|
||
| Buttons inserted via the visual editor use the `.block-button` class with `--solid` and `--outline` variants. The default layout styles these using your branding colors: | ||
|
|
||
| - **Solid buttons** (`.block-button--solid`) use `primary_color` as the background and `primary_color_contrast` as the text color. | ||
| - **Outline buttons** (`.block-button--outline`) use a transparent background with `primary_color` as the text and border color. | ||
|
|
||
| Each button's individual style attributes from the visual editor (font size, padding, border radius, etc.) are preserved. | ||
|
|
||
| ```css title="Visual editor button styling" | ||
| /* Light mode */ | ||
| .block-row--button_set-v1 .block-button--solid { | ||
| background-color: {{ vars.branding.primary_color | default: "#000000" }}; | ||
| color: {{ vars.branding.primary_color_contrast | default: "#FFFFFF" }}; | ||
| } | ||
|
|
||
| .block-row--button_set-v1 .block-button--outline { | ||
| background-color: transparent; | ||
| color: {{ vars.branding.primary_color | default: "#000000" }}; | ||
| border-color: {{ vars.branding.primary_color | default: "#000000" }}; | ||
| } | ||
|
|
||
| /* Dark mode */ | ||
| @media (prefers-color-scheme: dark) { | ||
| .block-row--button_set-v1 .block-button--solid { | ||
| background-color: {{ vars.branding.dark_primary_color | default: vars.branding.primary_color | default: "#000000" }} !important; | ||
| color: {{ vars.branding.dark_primary_color_contrast | default: vars.branding.primary_color_contrast | default: "#FFFFFF" }} !important; | ||
| } | ||
|
|
||
| .block-row--button_set-v1 .block-button--outline { | ||
| background-color: transparent !important; | ||
| color: {{ vars.branding.dark_primary_color | default: vars.branding.primary_color | default: "#000000" }} !important; | ||
| border-color: {{ vars.branding.dark_primary_color | default: vars.branding.primary_color | default: "#000000" }} !important; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| #### Why dark mode uses `!important` overrides | ||
|
|
||
| The visual editor renders button colors as static inline `style` attributes, which don't change between light and dark mode. The default layout uses `!important` in dark mode to override the inline styles injected by the visual editor. This means: | ||
|
|
||
| - **Light mode.** The button respects per-button colors set in the visual editor. | ||
| - **Dark mode.** The layout forces branding-aware colors to ensure readability. | ||
|
|
||
| If you need full control over button colors in dark mode, you can customize the dark mode styles in your layout or create a custom layout with your own button styling. | ||
|
|
||
| ### Injecting workflow run scope into a layout at runtime | ||
|
|
||
| You can reference workflow-run-scoped variables in your layout with standard Liquid syntax, as long as they appear _after_ `{{content}}` is first rendered. (For variables needed _above_ `{{content}}`, see [pre-content variables](/integrations/email/layouts#defining-pre-content-variables) below.) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -77,6 +77,71 @@ The following MJML tags do not have their HTML children wrapped: | |
| } | ||
| /> | ||
|
|
||
| ## Dark mode support in MJML layouts | ||
|
|
||
| MJML layouts support dark mode using the `prefers-color-scheme` media query. The Knock default MJML layout includes dark mode support out of the box, automatically swapping colors and images based on the user's system preference. | ||
|
|
||
| To add dark mode support to a custom MJML layout, include the color scheme meta tags in `<mj-head>` and define your dark mode styles in an `<mj-style>` block: | ||
|
|
||
| ```mjml title="MJML layout with dark mode support" | ||
| <mjml> | ||
| <mj-head> | ||
| <mj-raw> | ||
| <meta name="color-scheme" content="light dark" /> | ||
| <meta name="supported-color-schemes" content="light dark" /> | ||
| </mj-raw> | ||
| <mj-style> | ||
| :root { color-scheme: light dark; supported-color-schemes: light dark; } | ||
| @media (prefers-color-scheme: dark) { .email-wrapper, .email-body { | ||
| background-color: #262626 !important; } p, h1, h2, h3 { color: #ffffff | ||
| !important; } } | ||
| </mj-style> | ||
| </mj-head> | ||
| <mj-body> | ||
| <!-- layout content --> | ||
| </mj-body> | ||
| </mjml> | ||
| ``` | ||
|
|
||
| For swapping logos and icons in dark mode, see [Swapping logos and icons in dark mode](/integrations/email/layouts#swapping-logos-and-icons-in-dark-mode) in the email layouts documentation. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Repeated layouts links on MJML pageLow Severity This page already links to Additional Locations (1)Triggered by learned rule: Link Knock concepts on first mention only per page Reviewed by Cursor Bugbot for commit 5819a6a. Configure here. |
||
|
|
||
| ## Styling buttons in MJML layouts | ||
|
|
||
| The Knock default MJML layout styles buttons using your branding colors, with automatic dark mode support. This applies to both legacy `mj-button` components and visual editor buttons. | ||
|
|
||
| #### How branding colors are applied | ||
|
|
||
| - **Solid buttons** use `primary_color` as the background and `primary_color_contrast` as the text color. | ||
| - **Outline buttons** use a transparent background with `primary_color` as the text and border color. | ||
| - **Dark mode** uses `dark_primary_color` and `dark_primary_color_contrast` (falling back to the light mode values if not set). | ||
|
|
||
| ```mjml title="MJML branding-aware button styling" | ||
| <mj-style> | ||
| /* Light mode button styles */ .block-button--solid { background-color: {{ | ||
| vars.branding.primary_color | default: "#000000" }}; color: {{ | ||
| vars.branding.primary_color_contrast | default: "#FFFFFF" }}; } | ||
| .block-button--outline { background-color: transparent; color: {{ | ||
| vars.branding.primary_color | default: "#000000" }}; border-color: {{ | ||
| vars.branding.primary_color | default: "#000000" }}; } /* Dark mode overrides | ||
| */ @media (prefers-color-scheme: dark) { .block-button--solid { | ||
| background-color: {{ vars.branding.dark_primary_color | default: | ||
| vars.branding.primary_color | default: "#000000" }} !important; color: {{ | ||
| vars.branding.dark_primary_color_contrast | default: | ||
| vars.branding.primary_color_contrast | default: "#FFFFFF" }} !important; } | ||
| .block-button--outline { background-color: transparent !important; color: {{ | ||
| vars.branding.dark_primary_color | default: vars.branding.primary_color | | ||
| default: "#000000" }} !important; border-color: {{ | ||
| vars.branding.dark_primary_color | default: vars.branding.primary_color | | ||
| default: "#000000" }} !important; } } | ||
| </mj-style> | ||
| ``` | ||
|
|
||
| #### Why dark mode uses `!important` overrides | ||
|
|
||
| The visual editor renders button colors as static inline styles that don't change between light and dark mode. To ensure buttons remain readable on dark backgrounds, the layout uses `!important` in dark mode to override these inline styles. This means per-button colors from the visual editor are respected in light mode, while dark mode enforces branding-aware colors for readability. | ||
|
|
||
| For more details, see [Styling buttons](/integrations/email/layouts#styling-buttons) in the email layouts documentation. | ||
|
|
||
| ## Limitations | ||
|
|
||
| - **MJML layouts require the `<mjml>` root tag.** Layouts set to MJML mode must be valid MJML documents. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -45,13 +45,17 @@ Use the [tenant API methods](/api-reference/tenants) to create or update a tenan | |
|
|
||
| ### `TenantSettings` | ||
|
|
||
| | Property | Description | | ||
| | --------------------------------- | ---------------------------------------------------------------------------------------------------------- | | ||
| | `branding.primary_color` | A hex value for the primary color | | ||
| | `branding.primary_color_contrast` | A hex value for the contrasting color to use with the primary color | | ||
| | `branding.logo_url` | A fully qualified URL for an image to use as the logo of this tenant | | ||
| | `branding.icon_url` | A fully qualified URL for an image to use as the icon of this tenant | | ||
| | `preference_set` | A complete `PreferenceSet` to use as a default for all recipients with workflows triggered for this tenant | | ||
| | Property | Description | | ||
| | -------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | ||
| | `branding.logo_url` | A fully qualified URL for an image to use as the logo of this tenant | | ||
| | `branding.icon_url` | A fully qualified URL for an image to use as the icon of this tenant | | ||
| | `branding.dark_logo_url` | A fully qualified URL for the logo to use in dark mode. Defaults to `logo_url` if not set | | ||
| | `branding.dark_icon_url` | A fully qualified URL for the icon to use in dark mode. Defaults to `icon_url` if not set | | ||
| | `branding.primary_color` | A hex value for the primary color. Defaults to `#000000` | | ||
| | `branding.primary_color_contrast` | A hex value for the contrasting color to use with the primary color. Defaults to `#FFFFFF` | | ||
| | `branding.dark_primary_color` | A hex value for the primary color in dark mode. Defaults to `primary_color` if not set | | ||
| | `branding.dark_primary_color_contrast` | A hex value for the contrasting color in dark mode. Defaults to `primary_color_contrast` if not set | | ||
| | `preference_set` | A complete `PreferenceSet` to use as a default for all recipients with workflows triggered for this tenant | | ||
|
Comment on lines
+48
to
+58
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is only tangential to this PR, but should we ticket adding these properties to the OpenAPI spec so that they're included in
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah yep we should. Could you file ticket for that? |
||
|
|
||
| <Callout | ||
| type="alert" | ||
|
|
||


Uh oh!
There was an error while loading. Please reload this page.