스플리터
스플리터 (Splitter)
영역을 가로 또는 세로로 나누고, 각 영역의 크기를 자유롭게 드래그로 조절할 수 있게 해주는 컴포넌트입니다.
출처: 문서
본문
언제 사용하나요 (When To Use)
영역을 가로 또는 세로로 나눌 때 사용할 수 있습니다. 각 영역의 크기를 드래그로 자유롭게 조절해야 할 때, 그리고 영역의 최대·최소 너비와 높이를 지정해야 할 때 사용합니다.
예제 (Examples)
기본 (Basic)
패널 크기 초기화와 크기 제한을 설정합니다.
import React from 'react';
import { Flex, Splitter, Typography } from 'antd';
export const Desc: React.FC<Readonly<{ text?: string | number }>> = (props) => (
<Flex justify="center" align="center" style={{ height: '100%' }}>
<Typography.Title type="secondary" level={5} style={{ whiteSpace: 'nowrap' }}>
{props.text}
</Typography.Title>
</Flex>
);
const App: React.FC = () => (
<Splitter style={{ height: 200, boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)' }}>
<Splitter.Panel defaultSize="40%" min="20%" max="70%">
<Desc text="First" />
</Splitter.Panel>
<Splitter.Panel>
<Desc text="Second" />
</Splitter.Panel>
</Splitter>
);
export default App;
제어 모드 (Control mode)
스플리터의 크기를 제어합니다. 패널 중 하나가 resizable을 비활성화하면 드래그가 비활성화됩니다.
import React from 'react';
import { Button, Flex, Splitter, Switch, Typography } from 'antd';
const Desc: React.FC<Readonly<{ text?: string | number }>> = (props) => (
<Flex justify="center" align="center" style={{ height: '100%' }}>
<Typography.Title type="secondary" level={5} style={{ whiteSpace: 'nowrap' }}>
{props.text}
</Typography.Title>
</Flex>
);
const App: React.FC = () => {
const [sizes, setSizes] = React.useState<(number | string)[]>(['50%', '50%']);
const [enabled, setEnabled] = React.useState(true);
return (
<Flex vertical gap="medium">
<Splitter
onResize={setSizes}
style={{ height: 200, boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)' }}
>
<Splitter.Panel size={sizes[0]} resizable={enabled}>
<Desc text="First" />
</Splitter.Panel>
<Splitter.Panel size={sizes[1]}>
<Desc text="Second" />
</Splitter.Panel>
</Splitter>
<Flex gap="medium" justify="space-between">
<Switch
value={enabled}
onChange={() => setEnabled(!enabled)}
checkedChildren="Enabled"
unCheckedChildren="Disabled"
/>
<Button onClick={() => setSizes(['50%', '50%'])}>Reset</Button>
</Flex>
</Flex>
);
};
export default App;
세로 (Vertical)
세로 레이아웃을 사용합니다.
import React from 'react';
import { Flex, Splitter, Typography } from 'antd';
const Desc: React.FC<Readonly<{ text?: string | number }>> = (props) => (
<Flex justify="center" align="center" style={{ height: '100%' }}>
<Typography.Title type="secondary" level={5} style={{ whiteSpace: 'nowrap' }}>
{props.text}
</Typography.Title>
</Flex>
);
const App: React.FC = () => (
<Splitter vertical style={{ height: 300, boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)' }}>
<Splitter.Panel>
<Desc text="First" />
</Splitter.Panel>
<Splitter.Panel>
<Desc text="Second" />
</Splitter.Panel>
</Splitter>
);
export default App;
접기 가능 (Collapsible)
collapsible을 설정해 접기를 활성화합니다. min을 통해 접혔을 때 드래그로 펼칠 수 있는 크기를 제한할 수 있습니다.
import React, { useState } from 'react';
import { Flex, Splitter, Switch, Typography } from 'antd';
import type { SplitterProps } from 'antd';
const Desc: React.FC<Readonly<{ text?: string | number }>> = (props) => (
<Flex justify="center" align="center" style={{ height: '100%' }}>
<Typography.Title type="secondary" level={5} style={{ whiteSpace: 'nowrap' }}>
{props.text}
</Typography.Title>
</Flex>
);
const CustomSplitter: React.FC<Readonly<SplitterProps>> = ({ style, ...restProps }) => (
<Splitter style={{ boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)', ...style }} {...restProps}>
<Splitter.Panel collapsible min="20%">
<Desc text="First" />
</Splitter.Panel>
<Splitter.Panel collapsible>
<Desc text="Second" />
</Splitter.Panel>
</Splitter>
);
const App: React.FC = () => {
const [motion, setMotion] = useState(true);
return (
<Flex vertical gap="middle">
<Flex gap="middle">
<Switch
checked={motion}
onChange={setMotion}
checkedChildren="motion"
unCheckedChildren="motion"
/>
</Flex>
<CustomSplitter style={{ height: 200 }} collapsible={{ motion }} />
<CustomSplitter style={{ height: 300 }} orientation="vertical" collapsible={{ motion }} />
</Flex>
);
};
export default App;
접기 아이콘 제어 (Control collapsible icons)
collapsible.showCollapsibleIcon을 설정해 접기 아이콘의 표시 모드를 제어합니다.
import React, { useState } from 'react';
import { Flex, Radio, Splitter, Typography } from 'antd';
import type { RadioChangeEvent } from 'antd';
import type { CheckboxGroupProps } from 'antd/es/checkbox';
const Desc: React.FC<Readonly<{ text?: string | number }>> = (props) => (
<Flex justify="center" align="center" style={{ height: '100%' }}>
<Typography.Title type="secondary" level={5} style={{ whiteSpace: 'nowrap' }}>
{props.text}
</Typography.Title>
</Flex>
);
const options: CheckboxGroupProps<'auto' | boolean>['options'] = [
{ label: 'Auto', value: 'auto' },
{ label: 'True', value: true },
{ label: 'False', value: false },
];
const App: React.FC = () => {
const [showIconMode, setShowIconMode] = useState<'auto' | boolean>(true);
const onChange = (e: RadioChangeEvent) => {
setShowIconMode(e.target.value);
};
return (
<Flex vertical gap={20}>
<Flex gap={5}>
<p>ShowCollapsibleIcon: </p>
<Radio.Group options={options} value={showIconMode} onChange={onChange} />
</Flex>
<Splitter style={{ height: 200, boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)' }}>
<Splitter.Panel
collapsible={{ start: true, end: true, showCollapsibleIcon: showIconMode }}
min="20%"
>
<Desc text="First" />
</Splitter.Panel>
<Splitter.Panel collapsible={{ start: true, end: true, showCollapsibleIcon: showIconMode }}>
<Desc text="Second" />
</Splitter.Panel>
<Splitter.Panel collapsible={{ start: true, end: true, showCollapsibleIcon: showIconMode }}>
<Desc text="Third" />
</Splitter.Panel>
</Splitter>
</Flex>
);
};
export default App;
여러 패널 (Multiple panels)
여러 개의 패널입니다.
import React from 'react';
import { Flex, Splitter, Typography } from 'antd';
const Desc: React.FC<Readonly<{ text?: string | number }>> = (props) => (
<Flex justify="center" align="center" style={{ height: '100%' }}>
<Typography.Title type="secondary" level={5} style={{ whiteSpace: 'nowrap' }}>
Panel {props.text}
</Typography.Title>
</Flex>
);
const App: React.FC = () => (
<Splitter style={{ height: 200, boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)' }}>
<Splitter.Panel collapsible>
<Desc text={1} />
</Splitter.Panel>
<Splitter.Panel collapsible={{ start: true }}>
<Desc text={2} />
</Splitter.Panel>
<Splitter.Panel>
<Desc text={3} />
</Splitter.Panel>
</Splitter>
);
export default App;
복합 조합 (Complex combination)
복합 조합 패널로, 빠른 접기와 크기 변경 금지를 지원합니다.
import React from 'react';
import { Flex, Splitter, Typography } from 'antd';
const Desc: React.FC<Readonly<{ text?: string | number }>> = (props) => (
<Flex justify="center" align="center" style={{ height: '100%' }}>
<Typography.Title type="secondary" level={5} style={{ whiteSpace: 'nowrap' }}>
{props.text}
</Typography.Title>
</Flex>
);
const App: React.FC = () => (
<Splitter style={{ height: 300, boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)' }}>
<Splitter.Panel collapsible>
<Desc text="Left" />
</Splitter.Panel>
<Splitter.Panel>
<Splitter orientation="vertical">
<Splitter.Panel>
<Desc text="Top" />
</Splitter.Panel>
<Splitter.Panel>
<Desc text="Bottom" />
</Splitter.Panel>
</Splitter>
</Splitter.Panel>
</Splitter>
);
export default App;
지연 (Lazy)
지연(lazy) 모드로, 드래그 중에는 크기가 즉시 업데이트되지 않고 놓을 때 업데이트됩니다.
import React from 'react';
import { Flex, Space, Splitter, Typography } from 'antd';
const Desc: React.FC<Readonly<{ text?: string | number }>> = (props) => (
<Flex justify="center" align="center" style={{ height: '100%' }}>
<Typography.Title type="secondary" level={5} style={{ whiteSpace: 'nowrap' }}>
{props.text}
</Typography.Title>
</Flex>
);
const App: React.FC = () => (
<Space vertical style={{ width: '100%' }}>
<Splitter lazy style={{ height: 200, boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)' }}>
<Splitter.Panel defaultSize="40%" min="20%" max="70%">
<Desc text="First" />
</Splitter.Panel>
<Splitter.Panel>
<Desc text="Second" />
</Splitter.Panel>
</Splitter>
<Splitter
lazy
orientation="vertical"
style={{ height: 200, boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)' }}
>
<Splitter.Panel defaultSize="40%" min="30%" max="70%">
<Desc text="First" />
</Splitter.Panel>
<Splitter.Panel>
<Desc text="Second" />
</Splitter.Panel>
</Splitter>
</Space>
);
export default App;
커스터마이즈 (Customize)
핸들 요소와 스타일을 커스터마이즈합니다.
import React from 'react';
import {
CaretDownOutlined,
CaretLeftOutlined,
CaretRightOutlined,
CaretUpOutlined,
ColumnWidthOutlined,
} from '@ant-design/icons';
import { ConfigProvider, Divider, Flex, Splitter, Typography } from 'antd';
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => ({
dragger: {
'&::before': {
backgroundColor: 'transparent !important',
border: `${token.lineWidth}px dashed ${token.controlItemBgHover}`,
},
'&:hover::before': {
border: `${token.lineWidth}px dashed ${token.colorPrimary}`,
},
},
draggerActive: {
'&::before': {
border: `${token.lineWidth}px dashed ${token.colorPrimary}`,
},
},
draggerIcon: {
'&:hover': {
color: token.colorPrimary,
},
},
collapsibleIcon: {
fontSize: token.fontSizeLG,
color: token.colorTextDescription,
'&:hover': {
color: token.colorPrimary,
},
},
}));
const Desc: React.FC<Readonly<{ text?: string | number }>> = (props) => (
<Flex justify="center" align="center" style={{ height: '100%' }}>
<Typography.Title type="secondary" level={5} style={{ whiteSpace: 'nowrap' }}>
{props.text}
</Typography.Title>
</Flex>
);
const App: React.FC = () => {
const { styles } = useStyles();
return (
<ConfigProvider
theme={{
components: {
Splitter: { splitBarSize: 1, splitTriggerSize: 16 },
},
}}
>
<Splitter
style={{ height: 200, boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)' }}
draggerIcon={<ColumnWidthOutlined className={styles.draggerIcon} />}
collapsible={{
icon: {
start: <CaretLeftOutlined className={styles.collapsibleIcon} />,
end: <CaretRightOutlined className={styles.collapsibleIcon} />,
},
}}
>
<Splitter.Panel defaultSize="40%" min="20%" max="70%" collapsible>
<Desc text="Panel 1" />
</Splitter.Panel>
<Splitter.Panel collapsible>
<Desc text="Panel 2" />
</Splitter.Panel>
<Splitter.Panel resizable={false}>
<Desc text="Panel 3" />
</Splitter.Panel>
</Splitter>
<Divider />
<Splitter
orientation="vertical"
classNames={{ dragger: { default: styles.dragger, active: styles.draggerActive } }}
style={{ height: 200, boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)' }}
draggerIcon={null}
collapsible={{
icon: {
start: <CaretUpOutlined className={styles.collapsibleIcon} />,
end: <CaretDownOutlined className={styles.collapsibleIcon} />,
},
}}
>
<Splitter.Panel defaultSize="40%" min="30%" max="70%" collapsible>
<Desc text="First" />
</Splitter.Panel>
<Splitter.Panel collapsible>
<Desc text="Second" />
</Splitter.Panel>
</Splitter>
</ConfigProvider>
);
};
export default App;
커스텀 시맨틱 DOM 스타일링 (Custom semantic dom styling)
classNames와 styles에 객체 또는 함수를 넘겨서 Splitter의 시맨틱 DOM 스타일을 커스터마이즈할 수 있습니다.
import React from 'react';
import { Flex, Splitter, Typography } from 'antd';
import type { GetProp, SplitterProps } from 'antd';
import { createStaticStyles } from 'antd-style';
const Desc: React.FC<Readonly<{ text?: string | number; style?: React.CSSProperties }>> = (
props,
) => {
return (
<Flex justify="center" align="center" style={{ height: '100%' }}>
<Typography.Title type="secondary" level={5} style={props.style}>
{props.text}
</Typography.Title>
</Flex>
);
};
const styles = createStaticStyles(({ css, cssVar }) => ({
boxShadow: css`
box-shadow: ${cssVar.boxShadowSecondary};
`,
}));
const stylesObject: SplitterProps['styles'] = {
root: { backgroundColor: '#fffbe6' },
// dragger: { backgroundColor: 'rgba(194,223,252,0.4)' },
dragger: { default: { backgroundColor: 'rgba(194,223,252,0.4)' } },
};
const stylesFn: SplitterProps['styles'] = ({
props,
}): GetProp<SplitterProps, 'styles', 'Return'> => {
if (props.orientation === 'horizontal') {
return {
root: {
borderWidth: 2,
borderStyle: 'dashed',
marginBottom: 10,
},
};
}
return {};
};
const App: React.FC = () => {
const splitSharedProps: SplitterProps = {
style: { height: 200 },
classNames: { root: styles.boxShadow },
};
return (
<Flex vertical gap="large">
<Splitter {...splitSharedProps} styles={stylesObject}>
<Splitter.Panel>
<Desc text="First" style={{ color: '#000' }} />
</Splitter.Panel>
<Splitter.Panel>
<Desc text="Second" style={{ color: '#000' }} />
</Splitter.Panel>
</Splitter>
<Splitter {...splitSharedProps} styles={stylesFn}>
<Splitter.Panel>
<Desc text="First" />
</Splitter.Panel>
<Splitter.Panel>
<Desc text="Second" />
</Splitter.Panel>
</Splitter>
</Flex>
);
};
export default App;
더블클릭 리셋 (Double-clicked reset)
드래거를 더블클릭하면 Splitter.Panel을 기본 크기로 초기화합니다.
import React, { useState } from 'react';
import { Flex, Splitter, Typography } from 'antd';
const defaultSizes = ['30%', '40%', '30%'];
const Desc: React.FC<Readonly<{ text?: string | number }>> = (props) => (
<Flex justify="center" align="center" style={{ height: '100%' }}>
<Typography.Title type="secondary" level={5} style={{ whiteSpace: 'nowrap' }}>
Panel {props.text}
</Typography.Title>
</Flex>
);
const App: React.FC = () => {
const [sizes, setSizes] = useState<(number | string)[]>(defaultSizes);
const handleDoubleClick = () => {
setSizes(defaultSizes);
};
return (
<Splitter
style={{ height: 200, boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)' }}
onResize={setSizes}
onDraggerDoubleClick={handleDoubleClick}
>
<Splitter.Panel size={sizes[0]}>
<Desc text={1} />
</Splitter.Panel>
<Splitter.Panel size={sizes[1]}>
<Desc text={2} />
</Splitter.Panel>
<Splitter.Panel size={sizes[2]}>
<Desc text={3} />
</Splitter.Panel>
</Splitter>
);
};
export default App;
API
Common props ref:Common props
Splitter 컴포넌트는 자식 요소를 통해 패널 크기를 계산해야 하므로, 자식 요소는
Splitter.Panel만 지원합니다.
Splitter
| Property | Description | Type | Default | Version | Global Config |
|---|---|---|---|---|---|
| classNames | Customize class for each semantic structure inside the component. Supports object or function. | Record<SemanticDOM, string> | (info: { props })=> Record<SemanticDOM, string> | - | 6.0.0 | 6.0.0 |
| collapsible | motion to enable collapse animation, icon to customize collapse icons |
{ motion?: boolean; icon?: { start?: ReactNode; end?: ReactNode } } |
- | 6.4.0 | × |
| custom collapsible icon | {start?: ReactNode; end?: ReactNode} |
- | 6.0.0 | × | |
| destroyOnHidden | Destroy panel content when collapsed (size is 0). Applies to all panels, can be overridden per panel | boolean |
false |
6.4.0 | × |
| draggerIcon | custom dragger icon | ReactNode |
- | 6.0.0 | × |
| Layout direction | horizontal | vertical |
horizontal |
- | × | |
| lazy | Lazy mode | boolean |
false |
5.23.0 | × |
| onCollapse | Callback when expanding or collapsing | (collapsed: boolean[], sizes: number[]) => void |
- | 5.28.0 | × |
| orientation | Orientation direction | horizontal | vertical |
horizontal |
6.0.0 | × |
| styles | Customize inline style for each semantic structure inside the component. Supports object or function. | Record<SemanticDOM, CSSProperties> | (info: { props })=> Record<SemanticDOM, CSSProperties> | - | 6.0.0 | 6.0.0 |
| vertical | Orientation. Simultaneously existing with orientation, orientation takes priority |
boolean | false |
6.0.0 | × |
| onDraggerDoubleClick | Callback triggered when the dragger is double-clicked | (index: number) => void |
- | 6.3.0 | × |
| onResize | Panel size change callback | (sizes: number[]) => void |
- | - | × |
| onResizeEnd | Drag end callback | (sizes: number[]) => void |
- | - | × |
| onResizeStart | Callback before dragging starts | (sizes: number[]) => void |
- | - | × |
Panel
| Property | Description | Type | Default | Version |
|---|---|---|---|---|
| collapsible | Quick folding | boolean | { start?: boolean; end?: boolean; showCollapsibleIcon?: boolean | 'auto' } |
false |
showCollapsibleIcon: 5.27.0 |
| defaultSize | Initial panel size support number for px or 'percent%' usage | number | string |
- | - |
| destroyOnHidden | Destroy panel content when collapsed (size is 0). Overrides Splitter's destroyOnHidden |
boolean |
- | 6.4.0 |
| max | Maximum threshold support number for px or 'percent%' usage | number | string |
- | - |
| min | Minimum threshold support number for px or 'percent%' usage | number | string |
- | - |
| resizable | Whether to enable drag and drop | boolean |
true |
- |
| size | Controlled panel size support number for px or 'percent%' usage | number | string |
- | - |
시맨틱 DOM (Semantic DOM)
https://ant.design/components/splitter/semantic.md