Styling Generic Component with Styled Components

45 Views Asked by At

I'm running into annoying typescript errors when trying to style my generic component like follows:

const StyledParentComponent = styled(ParentComponent)`
  ${GenericComponent} {
    ...
  }
`;

It throws a bunch of errors about JSX not being assignable to some Interpolation type.

Here is a small example that produces the error:

import styled from "styled-components";

const ParentComponent = () => {
  return (
    <ParentComponentContainer>
      <GenericComponent value={10} />
    </ParentComponentContainer>
  );
};

interface GenericComponentProps<T> {
  value: T;
  className?: string;
}

const GenericComponent = <T,>({
  value,
  className,
}: GenericComponentProps<T>) => {
  console.log(value);

  return (
    <GenericComponentContainer>
      Logging generic component value
    </GenericComponentContainer>
  );
};

const GenericComponentContainer = styled.div``;

const RegularComponent = () => {
  return <RegularContainer></RegularContainer>;
};

const RegularContainer = styled.div``;

const ParentComponentContainer = styled.div` 
  // this is where it will throw the error
  ${GenericComponent} {
    display: flex;
  }

  ${RegularContainer} {
    display: flex;
  }
`;

I was running what the standard pattern is for dealing with this issue. It's important that I'm able to style it this way so that I can have generic components as children and be able to style them with the above pattern.

2

There are 2 best solutions below

0
Gak On

I think using React Component in styled.div() is very unusual. I've never seen it done before. How about we try this approach instead?

First, forward the className props to GenericComponentContainer.

const GenericComponent = <T,>({
  value,
  className,
}: GenericComponentProps<T>) => {
  console.log(value);

  return (
    // Must forward the `className` prop!
    <GenericComponentContainer className={className}>
      Logging generic component value
    </GenericComponentContainer>
  );
};

const GenericComponentContainer = styled.div``;

And then, styling GenericComponent with styled.

const ParentComponentContainer = styled.div` 
  ${RegularContainer} {
    display: flex;
  }
`;

const StyledGenericComponent = styled(GenericComponent)`
   display: flex;
`;

0
Beau On

I think your GenericComponent itself needs to be styled(GenericComponent) in order to be used within a style block.

We use something like this in our codebase.

const StyledGenericComponent = styled(GenericComponent)`
  color: green;
`;

const Container = styled.div`
  ${StyledGenericComponent} {
      color: red;
  }
`;

However to keep the generic types flowing through we have to use a satisfies.

const StyledGenericComponent = styled(GenericComponent)``
  satisfies typeof GenericComponent;