CSS Parts

Style SenseFolks surveys with ::part(). Shadow DOM blocks ordinary page selectors from reaching survey internals.

Use the part names listed in each component's reference.

Why does my page CSS not style the survey?

Shadow DOM isolates survey styles from your page.

A global button rule cannot style buttons inside a survey.

CSS Parts expose named elements for your stylesheet to target.

How do I use ::part()?

Use the component tag followed by ::part(name):

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;
}

Combine ::part() with :hover, :focus, or :focus-visible. Check browser support before targeting ::placeholder.

Shared Survey Parts

Use shared parts for your base theme, then add component-specific styles.

Part NameWhat It Targets
survey-containerThe outer wrapper. Set fonts, background colour, and padding here.
headingPrimary headings and titles
buttonAll button elements
next-buttonNext and Submit buttons specifically
back-buttonBack and Previous buttons
inputText input fields
form-fieldForm field containers
form-labelForm labels
error-messageValidation error messages
button-containerContainer wrapping navigation buttons

Check each component reference for supported parts.

Styling Recipes

Match Your Brand Colours

Define reusable brand colours:

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

/* 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: 400;
  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

Apply your font stack:

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

Follow the system colour preference:

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: var(--color__grey--450);
    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

Keep keyboard focus visible:

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

Respect reduced-motion preferences:

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

Adjust spacing for smaller screens:

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

Replace these variables with your brand values:

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: var(--color__grey--450);
  --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: 400;
  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;
}

Keep the Theme Safe and Accessible

  • Use CSS custom properties for theming

    Reuse variables such as --brand-primary across components.

  • Keep accessibility intact

    Keep text and controls readable, with visible keyboard focus.

  • Respect user preferences

    Support prefers-color-scheme, prefers-reduced-motion, and forced-colors.

  • Test across browsers

    Test your theme in the browsers your users use.

  • Avoid changing structural layout

    Changing display, position, or flex can break internal layout.

  • Stick to exposed parts only

    Use exposed parts; internal markup can change.

Browser Support

Minimum versions for ::part():

BrowserVersionNotes
Chrome73+Full support
Firefox72+Full support
Safari13.1+Full support
Edge79+Full support

Also check the component's browser requirements. IE11 is unsupported.

Related guides