CSS Parts

Surveys run in Shadow DOM, so regular page CSS cannot reach internal elements. CSS Parts provide the supported way to style those elements.

SenseFolks components expose named parts. Target them with ::part() to style buttons, headings, inputs, and containers.

The Problem

SenseFolks surveys use Shadow DOM to prevent style conflicts with your page.

The trade-off is that global selectors like button { background: red } do not affect internal survey elements.

CSS Parts are the official override path: we expose styleable elements, and you target those names from outside.

The ::part() Selector

The syntax is straightforward. Use the component tag plus ::part(name), where name is an exposed part:

css
/* Target a specific part by name */
sf-fastpoll::part(button) {
  background: #007bff;
  color: white;
}

/* Target multiple parts with the same styles */
sf-fastpoll::part(heading),
sf-fastpoll::part(subheading) {
  font-family: 'Georgia', serif;
}

/* Combine with pseudo-classes */
sf-fastpoll::part(button):hover {
  background: #0056b3;
}

sf-fastpoll::part(button):focus-visible {
  outline: 2px solid #007bff;
  outline-offset: 2px;
}

/* Combine with pseudo-elements (limited support) */
sf-fastpoll::part(input)::placeholder {
  color: #6c757d;
}

You can combine ::part() with pseudo-classes like :hover, :focus, and :focus-visible. Support for pseudo-elements like ::placeholder varies by browser.

Parts Available on Every Survey Component

All SenseFolks survey components share these common parts. Style them once to keep visual consistency across surveys:

Part Name What It Targets
survey-container The outer wrapper. Set fonts, background colour, and padding here.
heading Primary headings and titles
button All button elements
next-button Next and Submit buttons specifically
back-button Back and Previous buttons
input Text input fields
form-field Form field containers
form-label Form labels
error-message Validation error messages
button-container Container wrapping navigation buttons

Each survey type also exposes component-specific parts. Check the component references for the full list.

Styling Recipes

Match Your Brand Colours

Define CSS custom properties once, then apply them across every survey component on your site:

css
/* Define your brand variables */
:root {
  --brand-primary: #6366f1;
  --brand-primary-dark: #4f46e5;
  --brand-primary-light: #eef2ff;
  --brand-text: #1e293b;
  --brand-border: #e2e8f0;
}

/* Apply to all SenseFolks components */
sf-fastpoll::part(button),
sf-pricepoint::part(button),
sf-userchoice::part(button) {
  background: var(--brand-primary);
  border: none;
  border-radius: 8px;
  color: white;
  font-weight: 600;
  padding: 12px 24px;
  cursor: pointer;
  transition: background 0.2s;
}

sf-fastpoll::part(button):hover,
sf-pricepoint::part(button):hover,
sf-userchoice::part(button):hover {
  background: var(--brand-primary-dark);
}

Custom Typography

Swap in your own font stack so surveys read like the rest of your content:

css
/* Custom typography system */
sf-userchoice::part(survey-container) {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: 16px;
  line-height: 1.5;
  color: var(--brand-text);
}

sf-userchoice::part(heading) {
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin-bottom: 1rem;
}

sf-userchoice::part(choice-label) {
  font-size: 1rem;
  font-weight: 500;
}

Dark Mode

Detect the user's system preference, or wire it up to your own dark mode toggle:

css
/* Dark mode with system preference detection */
@media (prefers-color-scheme: dark) {
  sf-pricepoint::part(survey-container) {
    background: #1a1a2e;
    color: #e2e8f0;
  }

  sf-pricepoint::part(text-input) {
    background: #16213e;
    border-color: #374151;
    color: #f1f5f9;
  }

  sf-pricepoint::part(button) {
    background: #6366f1;
  }

  sf-pricepoint::part(button):hover {
    background: #818cf8;
  }

  sf-pricepoint::part(validation-message) {
    background: #7f1d1d;
    color: #fecaca;
  }
}

/* Manual dark mode toggle */
.dark sf-pricepoint::part(survey-container) {
  background: #1a1a2e;
  color: #e2e8f0;
}

Accessible Focus States

Keyboard users need visible focus indicators. Here's how to style them without cluttering mouse interactions:

css
/* Accessible focus indicators */
sf-openfeedback::part(input):focus,
sf-openfeedback::part(textarea):focus {
  outline: none;
  border-color: var(--brand-primary);
  box-shadow: 0 0 0 3px var(--brand-primary-light);
}

/* Focus-visible for keyboard users only */
sf-openfeedback::part(button):focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: 2px;
}

/* High contrast mode support */
@media (forced-colors: active) {
  sf-openfeedback::part(button) {
    border: 2px solid currentColor;
  }
}

Animations and Transitions

Add subtle motion to interactions, and respect users who prefer reduced motion:

css
/* Smooth transitions */
sf-fastpoll::part(choice-option) {
  transition: 
    border-color 0.2s ease,
    background-color 0.2s ease,
    transform 0.1s ease;
}

sf-fastpoll::part(choice-option):hover {
  border-color: var(--brand-primary);
  background: var(--brand-primary-light);
}

sf-fastpoll::part(choice-option):active {
  transform: scale(0.98);
}

/* Respect reduced motion preference */
@media (prefers-reduced-motion: reduce) {
  sf-fastpoll::part(choice-option) {
    transition: none;
  }
}

Responsive Sizing

Surveys should feel right on phones, tablets, and desktops:

css
/* Mobile-first responsive styling */
sf-featurepriority::part(survey-container) {
  padding: 1rem;
  font-size: 14px;
}

sf-featurepriority::part(kano-option) {
  padding: 12px;
  margin-bottom: 8px;
}

/* Tablet and up */
@media (min-width: 768px) {
  sf-featurepriority::part(survey-container) {
    padding: 2rem;
    font-size: 16px;
  }

  sf-featurepriority::part(kano-option) {
    padding: 16px;
    margin-bottom: 12px;
  }
}

/* Desktop */
@media (min-width: 1024px) {
  sf-featurepriority::part(survey-container) {
    max-width: 600px;
    margin: 0 auto;
  }
}

Full Theme Starter

Use this as a starting point and adjust variables to match your brand:

css
/* Complete theme example */
:root {
  --sf-primary: #6366f1;
  --sf-primary-hover: #4f46e5;
  --sf-bg: #ffffff;
  --sf-bg-secondary: #f8fafc;
  --sf-text: #1e293b;
  --sf-text-muted: #64748b;
  --sf-border: #e2e8f0;
  --sf-error: #ef4444;
  --sf-success: #22c55e;
  --sf-radius: 8px;
}

/* Container */
sf-fastpoll::part(survey-container) {
  background: var(--sf-bg);
  color: var(--sf-text);
  font-family: system-ui, sans-serif;
  border-radius: var(--sf-radius);
  padding: 1.5rem;
}

/* Headings */
sf-fastpoll::part(heading) {
  font-size: 1.25rem;
  font-weight: 600;
  margin-bottom: 1rem;
}

/* Choices */
sf-fastpoll::part(choice-option) {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 1rem;
  border: 2px solid var(--sf-border);
  border-radius: var(--sf-radius);
  margin-bottom: 0.5rem;
  cursor: pointer;
  transition: all 0.2s;
}

sf-fastpoll::part(choice-option):hover {
  border-color: var(--sf-primary);
  background: var(--sf-bg-secondary);
}

/* Buttons */
sf-fastpoll::part(button) {
  background: var(--sf-primary);
  color: white;
  border: none;
  border-radius: var(--sf-radius);
  padding: 0.75rem 1.5rem;
  font-weight: 600;
  cursor: pointer;
}

sf-fastpoll::part(button):hover {
  background: var(--sf-primary-hover);
}

sf-fastpoll::part(button):disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Error states */
sf-fastpoll::part(error-message) {
  color: var(--sf-error);
  font-size: 0.875rem;
  margin-top: 0.5rem;
}

Things to Keep in Mind

  • Use CSS custom properties for theming

    Define variables like --brand-primary once and reuse them across all survey components. Changing your brand colour becomes a one-line edit.

  • Keep accessibility intact

    Maintain sufficient colour contrast (4.5:1 for text, 3:1 for UI elements) and always provide visible focus states for keyboard navigation.

  • Respect user preferences

    Support prefers-color-scheme, prefers-reduced-motion, and forced-colors so your surveys work well for everyone.

  • Test across browsers

    CSS Parts work in all modern browsers, but always verify your custom styles render correctly.

  • Don't override layout properties

    Changing display, position, or flex on internal parts can break how the component arranges its elements.

  • Stick to exposed parts only

    Internal DOM structure may change between versions. Parts are the stable API for styling.

Browser Support

CSS Parts work in every modern browser:

Browser Version Notes
Chrome73+Full support
Firefox72+Full support
Safari13.1+Full support
Edge79+Full support

On older browsers, surveys fall back to their default styling. Nothing breaks, it just won't pick up your custom theme.

Next Steps