Featuring Design System
Legacy

CoreModal

모달 컴포넌트

Usage

기본 사용법

import { useState } from 'react';
import { CoreModal, CorePortal, CoreButton } from '@featuring-corp/components';

const [open, setOpen] = useState(false);

<>
  <CoreButton text="모달 열기" onClick={() => setOpen(true)} />
  {open && (
    <CorePortal>
      <CoreModal
        size="md"
        title="타이틀입니다."
        handleClose={() => setOpen(false)}
        actionsChildren={[
          <CoreButton 
            key="cancel"
            buttonType="contrast" 
            text="취소" 
            onClick={() => setOpen(false)} 
          />,
          <CoreButton 
            key="confirm"
            text="확인" 
            onClick={() => {
              console.log('확인');
              setOpen(false);
            }} 
          />,
        ]}
      >
        <div>모달 내용입니다.</div>
      </CoreModal>
    </CorePortal>
  )}
</>

크기 설정

import { useState } from 'react';
import { CoreModal, CorePortal, CoreButton } from '@featuring-corp/components';

const [open, setOpen] = useState(false);

{open && (
  <CorePortal>
    <CoreModal
      size="sm"
      title="작은 모달"
      handleClose={() => setOpen(false)}
    >
      <div>작은 크기의 모달입니다.</div>
    </CoreModal>
  </CorePortal>
)}

{open && (
  <CorePortal>
    <CoreModal
      size="md"
      title="중간 모달"
      handleClose={() => setOpen(false)}
    >
      <div>중간 크기의 모달입니다.</div>
    </CoreModal>
  </CorePortal>
)}

{open && (
  <CorePortal>
    <CoreModal
      size="lg"
      title="큰 모달"
      handleClose={() => setOpen(false)}
    >
      <div>큰 크기의 모달입니다.</div>
    </CoreModal>
  </CorePortal>
)}

위험 모달 (Danger Status)

import { useState } from 'react';
import { CoreModal, CorePortal, CoreButton } from '@featuring-corp/components';

const [open, setOpen] = useState(false);

{open && (
  <CorePortal>
    <CoreModal
      size="md"
      title="삭제 확인"
      status="danger"
      isOverlay={true}
      handleClose={() => setOpen(false)}
      actionsChildren={[
        <CoreButton 
          key="cancel"
          buttonType="contrast" 
          text="취소" 
          onClick={() => setOpen(false)} 
        />,
        <CoreButton 
          key="delete"
          buttonType="primary"
          text="삭제" 
          isDanger
          onClick={() => {
            // 삭제 로직
            setOpen(false);
          }} 
        />,
      ]}
    >
      <div>정말로 삭제하시겠습니까?</div>
    </CoreModal>
  </CorePortal>
)}

Overlay 없이 사용

import { useState } from 'react';
import { CoreModal, CorePortal, CoreButton } from '@featuring-corp/components';

const [open, setOpen] = useState(false);

{open && (
  <CorePortal>
    <CoreModal
      size="md"
      title="타이틀"
      isOverlay={false}
      handleClose={() => setOpen(false)}
      actionsChildren={[
        <CoreButton 
          key="cancel"
          buttonType="contrast" 
          text="취소" 
          onClick={() => setOpen(false)} 
        />,
        <CoreButton 
          key="confirm"
          text="확인" 
          onClick={() => setOpen(false)} 
        />,
      ]}
    >
      <div>Overlay 없이 표시되는 모달입니다.</div>
    </CoreModal>
  </CorePortal>
)}

액션 버튼 정렬 설정

import { useState } from 'react';
import { CoreModal, CorePortal, CoreButton } from '@featuring-corp/components';

const [open, setOpen] = useState(false);

{open && (
  <CorePortal>
    <CoreModal
      size="md"
      title="타이틀"
      actionsJustify="start"
      handleClose={() => setOpen(false)}
      actionsChildren={[
        <CoreButton 
          key="cancel"
          buttonType="contrast" 
          text="취소" 
          onClick={() => setOpen(false)} 
        />,
        <CoreButton 
          key="confirm"
          text="확인" 
          onClick={() => setOpen(false)} 
        />,
      ]}
    >
      <div>액션 버튼이 왼쪽 정렬됩니다.</div>
    </CoreModal>
  </CorePortal>
)}

{open && (
  <CorePortal>
    <CoreModal
      size="md"
      title="타이틀"
      actionsJustify="center"
      handleClose={() => setOpen(false)}
      actionsChildren={[
        <CoreButton 
          key="cancel"
          buttonType="contrast" 
          text="취소" 
          onClick={() => setOpen(false)} 
        />,
        <CoreButton 
          key="confirm"
          text="확인" 
          onClick={() => setOpen(false)} 
        />,
      ]}
    >
      <div>액션 버튼이 중앙 정렬됩니다.</div>
    </CoreModal>
  </CorePortal>
)}

{open && (
  <CorePortal>
    <CoreModal
      size="md"
      title="타이틀"
      actionsJustify="end"
      handleClose={() => setOpen(false)}
      actionsChildren={[
        <CoreButton 
          key="cancel"
          buttonType="contrast" 
          text="취소" 
          onClick={() => setOpen(false)} 
        />,
        <CoreButton 
          key="confirm"
          text="확인" 
          onClick={() => setOpen(false)} 
        />,
      ]}
    >
      <div>액션 버튼이 오른쪽 정렬됩니다.</div>
    </CoreModal>
  </CorePortal>
)}

{open && (
  <CorePortal>
    <CoreModal
      size="md"
      title="타이틀"
      actionsJustify="between"
      handleClose={() => setOpen(false)}
      actionsChildren={[
        <CoreButton 
          key="cancel"
          buttonType="contrast" 
          text="취소" 
          onClick={() => setOpen(false)} 
        />,
        <CoreButton 
          key="confirm"
          text="확인" 
          onClick={() => setOpen(false)} 
        />,
      ]}
    >
      <div>액션 버튼이 양쪽 정렬됩니다.</div>
    </CoreModal>
  </CorePortal>
)}

Props

Prop

Type

CoreModalSize

Prop

Type

CoreModalStatus

Prop

Type

CoreModalActionsJustify

Prop

Type

스타일

기본 스타일 속성

Modal Container:

  • position: fixed
  • top: 50%
  • left: 50%
  • transform: translate(-50%, -50%)
  • padding: spacing-600 (24px)
  • border-radius: radius-100
  • elevation: elevation-8
  • background-color: white

Wrapper:

  • display: flex
  • flex-direction: column
  • gap: spacing-300 (12px)
  • width: 100%
  • max-height: calc(100vh - var(--global-spacing-2000) - var(--global-spacing-1200)) (calc(100vh - 80px - 48px))

Header:

  • display: flex
  • justify-content: space-between
  • align-items: flex-start
  • gap: spacing-400 (16px)

Actions:

  • display: flex
  • gap: spacing-200 (8px)
  • padding-top: spacing-200 (8px)

Size Variants

SizeWidth
sm400px
md600px
lg960px

Overlay

  • position: fixed
  • top: 0
  • left: 0
  • width: 100vw
  • height: 100vh
  • background-color: black (40% opacity)

Title

  • typography: heading[4]
  • flex: 1
  • word-wrap: break-word
  • white-space: pre-wrap

Title Wrapper

  • display: flex
  • gap: spacing-200 (8px)

Status Icon

  • width: spacing-500 (20px)
  • height: spacing-500 (20px)
  • margin-top: spacing-100 (4px)
  • display: inline-block

Slot (Content)

  • typography: body[2]
  • flex: 1
  • overflow-x: hidden

Actions Justify

JustifyCSS justify-content
startflex-start
centercenter
endflex-end
betweenspace-between

Action Buttons Container

액션 버튼들 사이:

  • display: flex
  • gap: spacing-200 (8px)