Styling with CSS
Styling with CSS
You can change how the widget looks from your own stylesheet, without touching the survey. The widget
exposes two things on purpose: CSS variables (--rq-*) and named parts (::part()). Everything else
inside it is private and may change.
Two layers
Appearance options set colours from JavaScript or the Appearance
tab. Your CSS comes on top: a rule in your stylesheet on the widget's host beats the same value
from appearance.
The one selector
The widget's host element carries the attribute data-rawquotes. Every rule starts from it:
The host also carries data-rawquotes-survey-id="<survey id>". Add it to aim a rule at one survey:
[data-rawquotes][data-rawquotes-survey-id="YOUR-SURVEY-ID"].
[data-rawquotes] { /* variables go here */ }
[data-rawquotes]::part(button) { /* parts go here */ }
Anatomy
Each name below is a part you can target. Tick Show part names to see them on the drawing. This is a static illustration of the real widget, not the widget itself.
Extra names such as choice-radio, selected or button-primary sit on the same element as the base
name. card-header and close-button appear only on a phone (480 px wide or less).
The widget shows one question at a time; the drawing shows two at once. A rating tile is choice-glyph
(an emoji) or choice-square (a number). A chosen tile gets selected on both the choice and the tile.
The "not available" message on an inline host has no stage around it. card-top is added to
card when the launcher sits in a top corner.
Variables
Set these on [data-rawquotes].
| Variable | What it controls | Light default | Dark default | appearance field |
|---|---|---|---|---|
--rq-color-accent | Main buttons, the chosen option, the launcher | #4F46E5 | as light, or dark.accentColor | accentColor |
--rq-color-accent-contrast | Text and icons on the accent | #FFFFFF, from the accent's brightness | calculated from the accent in use | none |
--rq-color-bg | Card and panel background | #FFFFFF | #111827, or dark.backgroundColor | backgroundColor |
--rq-color-text | Text | #111827 | #F9FAFB, or dark.textColor | textColor |
--rq-color-border | Outlines of fields, options and the card | #E5E7EB | #374151 | none |
--rq-color-error | Validation and send errors | #dc2626 | #f87171 | none |
--rq-panel-border | Outline of an inline panel. The floating card ignores it and is outlined by --rq-color-border | none | 1px solid var(--rq-color-border) | none |
--rq-radius | Rounding of card, fields and buttons (number tiles use half) | 12px | as light | borderRadius |
--rq-font-family | Font of the whole widget | inherit (your page's font) | as light | fontFamily (presets only) |
--rq-tile-glyph-size, --rq-tile-glyph-font | Emoji rating tile: size and font size | 44px, 20px | as light | choiceSize |
--rq-tile-square-size, --rq-tile-square-font | Number rating tile: size and font size | 40px, 14px | as light | choiceSize |
Tile sizes for the other choiceSize values (emoji size / emoji font / number size / number font, in px):
compact: 32 / 14 / 28 / 12default: 44 / 20 / 40 / 14comfortable: 52 / 23 / 48 / 16large: 60 / 30 / 56 / 18xl: 72 / 36 / 64 / 20
--rq-color-accent-contrast does not follow when you change --rq-color-accent in CSS. A light accent
with the white default gives white text on yellow. Set the contrast colour yourself.Before and after
Drawn live from the variables above.
[data-rawquotes] {
--rq-color-accent: #be185d;
--rq-radius: 4px;
--rq-font-family: Georgia, serif;
}
The trap: a light accent without a matching contrast colour.
[data-rawquotes] { --rq-color-accent: #facc15; }
The fix: set the contrast colour as well.
[data-rawquotes] {
--rq-color-accent: #facc15;
--rq-color-accent-contrast: #111827;
}
Parts
Target a part with [data-rawquotes]::part(name).
| Part | Extra names on the same element | What it is |
|---|---|---|
launcher | launcher-open | The button that opens the card (floating) |
card | card-top | The floating card |
card-header | Card header (phone) | |
close-button | The close button (phone) | |
stage | Container of the views | |
section-title | The section title (sectionTitle) | |
panel | A question or state panel | |
prompt | The question text | |
thanks | The thank-you text | |
message | message-muted, message-error | A message |
error | A validation error | |
error-icon | The icon in that error | |
actions | actions-end, actions-stack | A row of buttons |
button | button-primary or button-secondary; and one role: button-next, button-back, button-submit, button-retry, button-close, button-answer-again, button-decline | A button |
choices | choices-inline | The list of options |
choice | choice-tile, choice-radio, choice-checkbox or choice-button; selected | One option, the whole row |
choice-glyph | selected | Emoji rating tile |
choice-square | selected | Number rating tile |
choice-control | selected | Box of a radio or checkbox option |
choice-label | The option's label | |
choice-badge | The tick of a chosen option | |
select | The dropdown | |
input | The one-line answer | |
textarea | The multi-line answer |
What ::part() cannot do
- It cannot be chained into descendant selectors:
::part(a) ::part(b)and::part(a) spando not work. This is why states are extra names: write::part(choice-control selected), not a selector that reaches into the option. :hover,:focus-visibleand::placeholderwork on a part.- The
rq-*class names inside the widget are private. Do not target them.
Dark mode
Three ways, from simplest:
- Follow the visitor's device.
colorScheme: 'auto', optionally withdarkcolours: Dark mode. - Follow your site's theme switch with JavaScript. Call
updatefrom the switch (recipe 4). - Follow your site's theme switch with CSS only. Style
html.dark [data-rawquotes](recipe 2). This needs no JavaScript, as long as your theme puts adarkclass on<html>.
Recipes
Each one is meant to be copied as it is.
1. Your colours and shape
[data-rawquotes] {
--rq-color-accent: #be185d;
--rq-color-accent-contrast: #ffffff;
--rq-radius: 4px;
--rq-font-family: Georgia, serif;
}
2. Dark mode behind your site's switch (CSS only)
html.dark [data-rawquotes] {
--rq-color-bg: #0b1020;
--rq-color-text: #e5e7eb;
--rq-color-border: #2a3350;
--rq-color-accent: #818cf8;
--rq-color-accent-contrast: #111827;
--rq-panel-border: 1px solid var(--rq-color-border);
}
--rq-panel-border only outlines an inline panel. The floating card is outlined by --rq-color-border, so there the line above changes nothing.
3. Dark colours with appearance.dark
rawquotes('init', {
surveyId: 'YOUR-SURVEY-ID',
appearance: {
colorScheme: 'auto',
accentColor: '#4f46e5',
dark: { backgroundColor: '#0b1020', textColor: '#e5e7eb', accentColor: '#818cf8' }
}
})
4. Your theme switch calls update
themeToggle.addEventListener('click', function () {
var dark = document.documentElement.classList.toggle('dark')
rawquotes('update', { appearance: { colorScheme: dark ? 'dark' : 'light' } })
})
5. A button variant and a chosen option
[data-rawquotes]::part(button-primary) {
text-transform: uppercase;
border-radius: 999px;
}
[data-rawquotes]::part(button-secondary):hover {
text-decoration: underline;
}
[data-rawquotes]::part(choice-control selected) {
background: #eef2ff;
}
[data-rawquotes]::part(choice-tile selected) {
transform: scale(1.05);
}
6. A bigger launcher
[data-rawquotes]::part(launcher) {
width: 64px;
height: 64px;
}
7. Language from the page, and when it changes
rawquotes('init', { surveyId: 'YOUR-SURVEY-ID', appearance: { language: 'auto' } })
// your site switched the page language:
rawquotes('update', { appearance: { language: 'auto' } })
8. Any font
fontFamily accepts only sans, serif and mono. Any other font goes through the variable:
[data-rawquotes] { --rq-font-family: 'Lora', Georgia, serif; }
Load the font on your page as you normally would; the widget inherits what the page can render.