본문 바로가기

Web Development/ETC

Typography 프리셋 구조 개선 정리

1. 현재 구조

Typography 프리셋을 함수형 컴포넌트로 정의하고, 내부에서 공통 Typography 컴포넌트에 스타일 props를 주입하는 방식.

const Typography = ({ children, ...props }) => (
  <StyledTypography {...props}>
    {children}
  </StyledTypography>
);

const StyledTypography = styled.div`
  font-family: 'SUIT', sans-serif;
  margin: 0;
  font-size: ${({ $fontSize }) => $fontSize};
  ...
`;

// 프리셋
export const Medium2Body2 = (props) => (
  <Typography fontSize="15px" {...props} />
);

현재 구조의 특징

  • 구조
    • 함수형 컴포넌트가 스타일 프리셋 역할을 함
    • 공통 Typography에 props를 주입하는 형태

장점

  • margin, padding 등 커스텀 prop을 받아 로직 처리하기 편함
  • 조건부 스타일 처리에 유연함

단점

  • as 사용 시 forwardedAs를 써야 하는 등 사용성이 복잡함
  • styled(Medium2Body2)처럼 재확장할 때 주의 필요
  • 프리셋마다 함수 래퍼가 늘어나 코드가 장황해짐

2. 개선된 구조

프리셋을 순수 styled-component로 정의하고,

공통 Typography 컴포넌트에 .attrs()를 사용해 프리셋 값을 주입하는 방식.

const Typography = styled.div`
  font-family: 'SUIT', sans-serif;
  margin: 0;

  /* 기본 폰트 속성 */
  font-size: ${({ fontSize }) => fontSize || '15px'};
  font-weight: ${({ fontWeight }) => fontWeight || 400};
  line-height: ${({ lineHeight }) => lineHeight || '150%'};
  letter-spacing: ${({ letterSpacing }) => letterSpacing || '-0.3px'};

  /* 스타일링 속성 */
  ${({ color }) => color && `color: ${color};`}
  ${({ align }) => align && `text-align: ${align};`}
  ${({ margin }) => margin && `margin: ${margin};`}
  ${({ padding }) => padding && `padding: ${padding};`}
`;

프리셋 정의 예시

export const Bold1Header = styled(Typography).attrs({
  as: 'h1',
  fontSize: '36px',
  fontWeight: 700,
  lineHeight: '130%',
  letterSpacing: '-0.72px',
})``;

Bold1Header.displayName = 'Bold1Header';

3. 개선된 구조의 장단점

장점

  • 함수 래퍼 제거로 코드가 간결해짐
  • as 사용 시 바로 태그 변경 가능
  • styled(Bold1Header) 형태의 재확장이 직관적
  • 프리셋 정의가 선언적으로 보이고 예측 가능
  • Typography 시스템을 디자인 토큰처럼 관리 가능

단점

  • 동적 로직 추가가 상대적으로 불편함
  • fontSize 같은 커스텀 prop을 쓰려면
  • ${props => props.fontSize} 또는 .attrs()를 직접 정의해야 함

4. .attrs()란?

.attrs()는 styled-components 라이브러리에서 제공하는 고유한 메서드로,

컴포넌트에 기본 props 또는 계산된 props를 미리 주입할 수 있다.

적용 대상

  • styled-component에만 사용 가능

5. .attrs()로 설정할 수 있는 속성 종류

  1. HTML 표준 속성
    • href, src, type, placeholder 등
  2. React 표준 속성
    • id, onClick, onChange 등
  3. styled-components 특수 속성
    • as
  4. 사용자 정의 Custom Props
    • color, fontSize, active 등
    • 스타일 로직에서 ${props => ...} 형태로 사용 가능

6. .attrs() 기본 사용법

선언 시점

const Box = styled.div.attrs(props => ({
  bg: props.isActive ? 'red' : 'blue',
}))`
  background: ${props => props.bg};
`;
  • props는 실제 렌더링 시 전달되는 props
  • <Box isActive /> → attrs 내부 로직이 실행됨

사용 시점

const App = () => {
  const [isActive, setIsActive] = useState(true);

  return <Box isActive={isActive} />;
};

7. .attrs() 사용 시 장점

1) 로직 분리

  • React 컴포넌트: 상태, 데이터, 이벤트 관리
  • Styled Component: 화면 표현과 스타일 책임

2) Default Props 역할

const PasswordInput = styled.input.attrs({
  type: 'password',
})``;

// 사용
<PasswordInput />

8. .attrs() 종합 예시

styled.input.attrs({
  // 1. HTML 속성
  type: 'text',

  // 2. React 속성
  className: 'my-input-class',

  // 3. styled-components 특수 속성
  as: 'input',

  // 4. Custom Prop (스타일에서 사용)
  $isFocus: true,
})`
  background: ${props => (props.$isFocus ? 'white' : 'gray')};
`;

9. 결론

  • Typography 프리셋은 순수 styled-component + attrs 기반이 구조적으로 더 안정적
  • 디자인 시스템 관점에서 선언적이고 확장성이 좋음
  • 복잡한 조건 로직이 필요한 경우에만 함수형 컴포넌트 사용을 고려하는 것이 적절함