Search code examples
reactjstypescriptstyled-componentsemotion

React & Typescript, styled components & children


I've tried so many different combinations to get this to work, but it's not applying the styles I've written for the StyledLines component, by them selves they work fine! Using the StyledLines component as a child, it doesn't work. The Target component styles work as expected.

import React, { Fragment, FunctionComponent } from 'react';
import styled from '@emotion/styled';


interface Crosshair {
  size: number;
  thickness: number;
}


const Target = styled.div<Crosshair>`
  position:absolute;
  &:before {
    content: '';
    display:block;
    position:absolute;
    top:50%;
    left:50%;
    background-color:transparent;
    border-color:#2fd5d5;
    margin-left:-${({size}) => size / 4}px;
    margin-top:-${({thickness}) => thickness / 4}px;
    width:${({size}) => size / 2}px;
    height:${({thickness}) => thickness / 2}px;
  }
`;

const Lines: FunctionComponent = ({children}) => <div className="line">{children}</div>;

const StyledLines = styled(Lines)<Crosshair>`
  position:absolute;
  &:nth-of-type(1) {
    top:0;
    left:0;
  }
  &:nth-of-type(2) {
    top:0;
    right:0;
  }
  &:nth-of-type(3) {
    bottom:0;
    right:0;
  }
  &:nth-of-type(4) {
    bottom:0;
    left:0;
  }
  &:after, &:before {
    content: '';
    display:block;
    position:absolute;
    top:50%;
    left:50%;
    background:#2fd5d5;
    margin-left:-${({size = 2}) => size / 2}px;
    margin-top:-${({thickness = 24}) => thickness / 2}px;
    width:${({size = 2}) => size}px;
    height:${({thickness = 24}) => thickness}px;
  }
  &:before {
    transform: rotateZ(90deg);
  }
`;


export default function Crosshairs() {
  return <Fragment>
    <div>
      {[0,1,2,3].map(i => <StyledLines key={i} size={24} thickness={2}>
        <Target size={24} thickness={2} />
      </StyledLines>)}
    </div>
  </Fragment>;
}

Solution

  • Lines is a plain React component, not a styled component, so you have to pass the className prop to the DOM part you want to style:

    const Lines: FunctionComponent = ({children, className}) => <div className={`line ${className}`}>{children}</div>;