Slot
주어진 Props를 직계 자식 컴포넌트에 병합하고, 자식 컴포넌트를 렌더링하는 컴포넌트입니다.
Slot은 부모 컴포넌트의 기능을 자식 컴포넌트와 합성하는 합성(Composition)
패턴을 구현합니다. 이를 통해:
- 부모 컴포넌트의
props
,ref
,이벤트 핸들러
등을 자식 컴포넌트에 전달할 수 있습니다 - 자식 컴포넌트의 구현을 변경하지 않고도 새로운 기능을 추가할 수 있습니다
- 컴포넌트 간의 결합도를 낮추고 재사용성을 높일 수 있습니다
예를 들어 InView 나 AspectRatio 와 같은 컴포넌트에서 asChild
prop을 사용해서, 래퍼 요소 없이 자식 컴포넌트에 직접 기능을 주입할 수 있습니다.
Slot은 아래와 같은 특징이 있습니다.
- 자식 요소로
단일 요소
만 허용됩니다.
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>
- 자식 요소로 컴포넌트가 온다면 해당 컴포넌트는 필수적으로
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>