Skip to main content

Slot

주어진 Props를 직계 자식 컴포넌트에 병합하고, 자식 컴포넌트를 렌더링하는 컴포넌트입니다.

Slot은 부모 컴포넌트의 기능을 자식 컴포넌트와 합성하는 합성(Composition) 패턴을 구현합니다. 이를 통해:

  • 부모 컴포넌트의 props, ref, 이벤트 핸들러 등을 자식 컴포넌트에 전달할 수 있습니다
  • 자식 컴포넌트의 구현을 변경하지 않고도 새로운 기능을 추가할 수 있습니다
  • 컴포넌트 간의 결합도를 낮추고 재사용성을 높일 수 있습니다

예를 들어 InViewAspectRatio 와 같은 컴포넌트에서 asChild prop을 사용해서, 래퍼 요소 없이 자식 컴포넌트에 직접 기능을 주입할 수 있습니다.

Slot은 아래와 같은 특징이 있습니다.

  1. 자식 요소로 단일 요소만 허용됩니다.
typescript
// 가능
<Slot>
<div>Contents</div>
</Slot>

// 가능
<Slot>
<div>
<div>Contents1</div>
<div>Contents2</div>
</div>
</Slot>
typescript
// 불가능
<Slot>
<div>Contents1</div>
<div>Contents2</div>
</Slot>
  1. 자식 요소로 컴포넌트가 온다면 해당 컴포넌트는 필수적으로 forwardRef, props를 허용해야 합니다. 허용하지 않으면 기능이 정상적으로 동작하지 않습니다.
typescript
const MyButton = React.forwardRef((props, forwardedRef) => (
<button {...props} ref={forwardedRef} />
));

<Slot>
<MyButton>Button</MyButton>
</Slot>

Code

🔗 실제 구현 코드 확인

Interface

typescript
const Slot: React.ForwardRefExoticComponent<
React.HTMLAttributes<HTMLElement> & {
children?: React.ReactNode;
} & React.RefAttributes<HTMLElement>
>;
typescript
const Slottable: ({ children }: React.PropsWithChildren) => JSX.Element;

Usage

Default

typescript
import { Slot } from '@modern-kit/react'

const Button = ({
asChild,
...props
}: PropsWithChildren<{ asChild?: boolean } & ComponentProps<'button'>>) => {
const Comp = asChild ? Slot : 'button';

return <Comp {...props} />;
};

With Slottable

typescript
const SlottableButton = ({
asChild,
leftElement,
rightElement,
...props
}: PropsWithChildren<
{
asChild?: boolean;
leftElement: ReactElement;
rightElement: ReactElement;
} & ComponentProps<'button'>
>) => {
const Comp = asChild ? Slot : 'button';

return (
<Comp {...props}>
{leftElement}
<Slottable>{props.children}</Slottable>
{rightElement}
</Comp>
);
};

Example

Default

typescript
// Basic Usage
<Button onClick={() => console.log('click')}>Button</Button>

AsChild

typescript
// AsChild Usage
<Button asChild onClick={() => console.log('click')}>
<div>asChild Button</div>
</Button>
asChild Button

Slottable

typescript
<SlottableButton leftElement={<span>left</span>} rightElement={<span>right</span>}>
<span> Slottable Button </span>
</SlottableButton>