> For the complete documentation index, see [llms.txt](https://sunmermi.gitbook.io/blog/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sunmermi.gitbook.io/blog/section/react/dynamic-tag-name-props.md).

# Dynamic Tag Name Props

#### 상황

[Vue > Dynamic Components](https://app.gitbook.com/s/DPKt0tyjAJEzGVm6AJue/~/changes/9ZqzoNhp827M1R8hnw4Q/vue/dynamic-components-is-attribute) 의 연장선으로 작성하게 되었다.

위에 내용은 뷰에서 한개의 컴포넌트로 조건에 따라 렌더링 되는 태그를 변경하고 싶었다.

이전에 리액트에서 작업할 때는 `styled-components` 사용을 하고 있었기 때문에  `styled-components` 제공하는 `as` 프롭을 사용해서 쉽게 렌더링 태그를 변경할 수 있었다.

하지만 `styled-components` 사용하지 않는다면? 어떻게 해야하나? 궁금증이 생겼다.

#### `styled-components` 사용시

아래와 같이 `as` 를 사용하면 된다.

```tsx
// button 컴포넌트
<button 
  as={href && 'a'}
  className={ href ? 'link' : 'button'}
  {...props}
> {children} </button>

// 사용시
<Button as="a" href="/">a 태그로 렌더링</Button> 
<Button>button 태그로 렌더링</Button> 
```

####

#### React 사용으로만 구현하기 &#x20;

구글링을 했을땐 제일 많이 나오는 방법은 [이 방법](https://blog.hackages.io/conditionally-wrap-an-element-in-react-a8b9a47fab2)이였고

내가 원하는 방법은 [Dynamic Tag Name Props in React (with TypeScript)](https://www.aleksandrhovhannisyan.com/blog/dynamic-tag-name-props-in-react/) 이거다.

위 방법을 참고해서 직접 테스트 해본 [코드샌드박스](https://codesandbox.io/s/react-dynamic-tag-render-hjtvb9) &#x20;

**1. DynamicTag 컴포넌트 만들기**

```tsx
interface Props
  extends React.AllHTMLAttributes<any>,
    PropsWithChildren<unknown> {
  children?: React.ReactNode;
  className?: string;
  tagName?: React.ElementType<any>;
}

export const DynamicTag = ({
  children,
  tagName: Tag = "div",
  className,
  ...props
}: Props): ReactElement => {
  return (
    <Tag className={className} {...props}>
      {children}
    </Tag>
  );
};
```

**2. DynamicTag 컴포넌트를 사용해서 Button 만들기**

```tsx
import { DynamicTag } from "./dynamicTag";

interface Props extends PropsWithChildren<unknown> {
  className?: string;
  href?: string | undefined;
}

export const Button = ({
  children,
  href,
  className,
  ...props
}: Props): ReactElement => {
  return (
    <DynamicTag
      tagName={href ? "a" : "button"}
      className={className}
      href={href}
      {...props}
    >
      {children}
    </DynamicTag>
  );
};
```

**3. DynamicTag, Button 컴포넌트 사용하기**

```tsx
// DynamicTag 컴포넌트
<DynamicTag tagName="a" href="/">
  a 로 렌더링
</DynamicTag>
<DynamicTag tagName="p"> p 로 렌더링 </DynamicTag>
<DynamicTag> div 로 렌더링 </DynamicTag>

// Button 컴포넌트
<Button href="/">a 렌더링</Button>
<Button>button 렌더링</Button>
```

####

#### 더 연구해 볼 것

사실 위와 같은 방법이 올바른 방법인지는 모르겠다. 참고해서 작업하긴 했지만 오류에 계속 직면했다.

예를 들면 `DynamicTag` 컴포넌트에서 `...props` 를 전달하였음에도 `href` 속성값을 넣으면 `ts` 오류가 떴다. 다른 속성값도 마찬가지로 오류가 뜸.

구글링을 해보고 이리저리 껴 맞춰보고 해서 오류는 안뜨게 했는데 논리적으로 왜 저렇게 해야하는 건지 사실 방법은 잘 모른다. :sob:

`React.AllHTMLAttributes` 흠..

```tsx
// DynamicTag 에서 Props
interface Props extends React.AllHTMLAttributes<any> {
  children?: React.ReactNode;
  className?: string;
  tagName?: React.ElementType<any>;
}

// 사용시
<DynamicTag tagName="a" href="/">
  a 로 렌더링
</DynamicTag>
```

####

#### 참고

* [Dynamic Tag Name Props in React (with TypeScript)](https://www.aleksandrhovhannisyan.com/blog/dynamic-tag-name-props-in-react/)
* [How to conditionally wrap an element in React](https://blog.hackages.io/conditionally-wrap-an-element-in-react-a8b9a47fab2)
* [Writing Type-Safe Polymorphic React Components (Without Crashing TypeScript)](https://blog.andrewbran.ch/polymorphic-react-components/)
* [babel-plugin-react-html-attrs](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/78120d1d515a1cd7bcd3145424b1a17be15310a9/types/babel-plugin-react-html-attrs/index.d.ts#L1742)
* [AllHTMLAttributes](https://www.programcreek.com/typescript/?api=react.AllHTMLAttributes)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://sunmermi.gitbook.io/blog/section/react/dynamic-tag-name-props.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
