1

MWE

https://codesandbox.io/s/slider-example-ev250?file=/src/App.js

Question

I am attempting to create an <input type='range'> Styled Component that has a custom appearance:

const SliderInput = styled.input.attrs((props) => {
  const val = Number(props.value ?? 0);
  const min = Number(props.min ?? 0);
  const max = Number(props.max ?? 1);
  const breakpoint = 100 * ((val - min) / (max - min));

  return {
    style: {
      background: `linear-gradient(to right, ${props.color}, ${props.color} ${breakpoint}%, white ${breakpoint}%, white 100%)`,
      border: `solid 1px ${props.color}`
    }
  };
})`
  -webkit-appearance: none;
  width: 200px;
  height: 8px;
  border-radius: 12px;

  &::-webkit-slider-thumb {
    -webkit-appearance: none;
    background: ${(props) => props.color};
    border: 2px solid white;
    border-radius: 50%;
    width: 16px;
    height: 16px;
  }

  &:hover {
    cursor: grab;
  }
`;

The issue I am facing is that the background color of the thumb slider changes too frequently, which causes lagging and I see the following warning:

Over 200 classes were generated for component styled.input with the id of "sc-dlnjwi".
Consider using the attrs method, together with a style object for frequently changed styles.
Example:
  const Component = styled.div.attrs(props => ({
    style: {
      background: props.background,
    },
  }))`width: 100%;`

How can this be achieved with pseudo-selectors like ::-webkit-slider-thumb?

I've tried:

style: {
      background: `linear-gradient(to right, ${props.color}, ${props.color} ${breakpoint}%, white ${breakpoint}%, white 100%)`,
      border: `solid 1px ${props.color}`
      "::WebkitSliderThumb": {
        background: props.color
      }
    }

To no avail.

Any suggestions?

lbragile
  • 7,549
  • 3
  • 27
  • 64
  • I have copy/pasted your first snippet into a codesandbox and I don't see any such warnings, so it's a bit unclear what the issue may be. Are you sure the warning is from this component? Also, why are you specifying the CSS and using a `style` prop in the `.attrs`? – Drew Reese Aug 23 '21 at 04:31
  • Yes, I also tried in a sandbox and I don't see the warning. However, I am 100% sure this causes lag with my setup as when I remove the background of the slider, I no longer get the warning or see any lag. I will try putting together a sandbox to highlight the issue more clearly. – lbragile Aug 23 '21 at 04:32
  • I've added a MWE to the description above. If you move one of the inputs quickly (a couple of times), and then the other, you will see the warning in the console. I have a color wheel, which changes the slider's value based on the color under the user's mouse position. When I do it too quickly, I get the warning and lag is visible. I don't think this can be avoided with hooks like `useCallback` since my values change frequently and are real numbers. Any ideas? – lbragile Aug 23 '21 at 04:54
  • "Also, why are you specifying the CSS and using a style prop in the .attrs?" That is what the warning suggests to do. From my understanding this is equivalent to inline styles and should be done to avoid generating many components (with different classes). Thus, any prop that changes frequently is put in the `style` prop. Is this not the case? – lbragile Aug 23 '21 at 05:00

1 Answers1

1

It's not possible to style psuedo-selectors using inline styles (see this SO thread for more context). In other words, this isn't possible:

<input type="range" style="::WebkitSliderThumb:background:red" />

That's what styled-components's .attrs is doing under the hood, it's just applying inline styles [docs].

The only way to apply styles to psuedo-selectors is to use CSS, and as you've already seen it's not practical to do this with styled-components. I'd suggest determining a fixed number of slider steps, generating CSS classes for each of those ahead of time (you can use a preprocessor like SASS to do this effeciently), and then just dynamically applying the correct class when the slider's value changes.

superhawk610
  • 2,457
  • 2
  • 18
  • 27