Qaid
ARTICLE

Style the Quests Embed

Colours, fonts, presets, light and dark, --qaid-q tokens, custom CSS and saved themes for @qaiddev/quests-embed.

Qaid Team
TL;DR

The quest draws in a shadow root, so your page’s CSS cannot reach it. Style it with the colors option, a preset, a forced light or dark theme, --qaid-q-* tokens in css, or a saved quest theme. unstyled strips every default so only your CSS paints.

The quest draws inside a shadow root, so rules in your page’s stylesheet cannot reach it. Everything below goes in through the embed’s own options. Its tokens are named --qaid-q-*, apart from the thumbs embed’s, so a page running both can style each on its own.

To build a quest and paste its snippet, start with Getting started with quests.

The styling options

import { QaidQuests } from "@qaiddev/quests-embed";

new QaidQuests({
  endpoint: "https://qaid.dev/api/quests/responses",
  configUrl: "https://qaid.dev/api/quests/YOUR_QUEST_ID/definition",
  apiKey: "YOUR_PROJECT_KEY",
  container: "#quest-mount",
  colors: { accent: "#2D5A3D", error: "#B43E2C", focus: "#D4A24C" },
  fontFamily: "'Manrope', system-ui, sans-serif",
  preset: "pill",
  theme: "light",
});
Option Data attribute Default Sets
colors.accent data-positive-color #10b981 The Next and Submit button, the progress fill, a chosen option’s border, tint and dot, the slider thumb and value, the thank-you tick
colors.error data-negative-color #ef4444 Validation messages
colors.focus data-marker-color #6366f1 The focus ring on inputs, buttons, options and the slider
fontFamily data-font-family system-ui, -apple-system, sans-serif The typeface. The embed loads no fonts, so load a web font in your page first
fontSize data-font-size 16 The base size in pixels
preset data-preset "default" minimal is flat with square corners and no shadow; pill rounds buttons, options and inputs fully; dense tightens padding
theme data-theme "auto" "auto" follows the visitor’s system; "light" or "dark" pins it
css data-css-selector none Your own rules and tokens, below
themeUrl data-theme-url none A saved quest theme, below
unstyled data-unstyled false Strips the look, below

Text on the button turns black or white, whichever reads better on your accent. The old colour keys positive, negative and marker still work, and the data attributes still use those names.

Loading the film…

Change one part with tokens

Tokens are CSS variables. Set them in css, on .qaid-q-root:

css: `
  .qaid-q-root {
    --qaid-q-card-radius: 0;
    --qaid-q-btn-radius: 9999px;
    --qaid-q-card-bg: light-dark(#fffdf7, #1b1f1c);
  }
`,
Loading the film…

light-dark(a, b) gives one value in light mode and another in dark. Every token the embed reads:

/* Card */
--qaid-q-card-bg  --qaid-q-card-fg  --qaid-q-card-border
--qaid-q-card-radius  --qaid-q-card-padding  --qaid-q-card-shadow

/* Buttons */
--qaid-q-btn-radius  --qaid-q-btn-padding-y  --qaid-q-btn-padding-x
--qaid-q-btn-font-size  --qaid-q-btn-font-weight
--qaid-q-btn-primary-bg  --qaid-q-btn-primary-fg  --qaid-q-btn-primary-border
--qaid-q-btn-secondary-bg  --qaid-q-btn-secondary-fg
--qaid-q-btn-secondary-border  --qaid-q-btn-secondary-hover-bg

/* Choice cards */
--qaid-q-option-bg  --qaid-q-option-bg-selected  --qaid-q-option-bg-hover
--qaid-q-option-fg  --qaid-q-option-border  --qaid-q-option-border-selected
--qaid-q-option-border-hover  --qaid-q-option-radius  --qaid-q-option-padding

/* Radio dot and checkbox */
--qaid-q-marker-bg  --qaid-q-marker-bg-selected  --qaid-q-marker-border
--qaid-q-marker-icon  --qaid-q-marker-radius

/* Text boxes */
--qaid-q-input-bg  --qaid-q-input-fg  --qaid-q-input-border
--qaid-q-input-radius  --qaid-q-input-padding  --qaid-q-input-placeholder

/* Everything else */
--qaid-q-muted-fg  --qaid-q-progress-track  --qaid-q-gap  --qaid-q-section-gap

With a script tag, put the CSS in a <style> element and point data-css-selector at it. media="not all" keeps your page from applying it too:

<style id="quest-theme" media="not all">
  .qaid-q-root { --qaid-q-card-radius: 0; }
</style>
<script
  src="https://unpkg.com/@qaiddev/quests-embed"
  defer
  data-api-key="YOUR_PROJECT_KEY"
  data-endpoint="https://qaid.dev/api/quests/responses"
  data-config-url="https://qaid.dev/api/quests/YOUR_QUEST_ID/definition"
  data-css-selector="#quest-theme"
></script>

In a JSON config block the key is cssSelector.

Use a saved quest theme

A theme made in the dashboard is a hosted document of tokens, CSS and settings. Customize writes its URL into your snippet as themeUrl; see Design and publish a quest theme.

The embed fetches the theme alongside the quest. If the fetch fails, the quest still draws, with the defaults. themeDocument takes the same document as an object, for a server that fetched it already.

Later layers win. The built-in stylesheet comes first, then the theme’s tokens, the preset, the theme’s CSS, and last your page’s css. A preset, theme, unstyled, colour or font set on the page replaces the saved theme’s value.

Take over completely

With unstyled: true, you draw every part yourself. Style these classes:

/* Frame */
.qaid-q-card, .qaid-q-header, .qaid-q-title, .qaid-q-description,
.qaid-q-step-counter, .qaid-q-progress, .qaid-q-progress-fill {}

/* One question */
.qaid-q-step, .qaid-q-label, .qaid-q-error {}
.qaid-q-input, .qaid-q-textarea, .qaid-q-currency, .qaid-q-currency-prefix,
.qaid-q-range-wrap, .qaid-q-range, .qaid-q-range-value {}
.qaid-q-options, .qaid-q-option, .qaid-q-option.qaid-q-selected,
.qaid-q-option-marker, .qaid-q-option-body, .qaid-q-option-label, .qaid-q-option-desc {}

/* Buttons and the end screen */
.qaid-q-footer, .qaid-q-btn, .qaid-q-btn-primary, .qaid-q-btn-secondary {}
.qaid-q-done, .qaid-q-done-icon, .qaid-q-done-title, .qaid-q-done-message, .qaid-q-saving {}

/* The retry screen when sending fails (1.5.3 or later) */
.qaid-q-submit-error, .qaid-q-submit-error-title,
.qaid-q-submit-error-message, .qaid-q-submit-error-actions {}

The same classes work without unstyled, for a change no token covers.

Fit an inline form

Inline, the quest takes the width of its container. Give the container a fixed height and the card fills it: the body scrolls inside, with a fade and a cue when more is below. Under about 360px of height, image choices and gaps shrink to fit.

  1. progressPosition: "bottom" moves the step counter and bar into the footer, beside the buttons, so the question sits higher. The quest’s own Position setting does the same from the dashboard; the page option wins.
  2. Hide Header and Hide Progress in the quest editor remove the title row and the counter. A one-question quest never shows progress.
  3. modalWidth, backdropOpacity and zIndex do nothing inline.

Preview inside a page builder

In an editor’s preview pane, set autoFocus: false so the first step does not pull focus from the editor, and animate: false so the step does not slide in on every rebuild. To show edits, call quest.update(newQuestionnaire) instead of building a new embed; it redraws in place and never moves focus.

Back to all articles