Dialog
Alert
사용자 확인이 필요한 단순 알림. Promise를 반환하는 명령형 API입니다.
import { alert } from '@woon-ui/dialog'alert()은 사용자에게 정보를 전달하고 확인을 기다리는 함수입니다.
Promise<void>를 반환하며, 버튼 클릭이든 ESC든 닫히면 resolve됩니다.
앱 루트에 DialogRuntime이 있으면 어디서든 호출할 수 있습니다.
기본 사용법
import { alert } from '@woon-ui/dialog'
// 단순 알림
await alert({ title: '저장되었습니다' })
// 설명 포함
await alert({
title: '파일이 삭제되었습니다',
description: '휴지통에서 복구할 수 있습니다.',
})Preview
옵션
| Prop | Type | Default |
|---|---|---|
| title | ReactNode | — |
| 알림 제목 | ||
| description | ReactNode | — |
| 알림 설명 | ||
| confirmLabel | ReactNode | '확인' |
| 확인 버튼 텍스트 | ||
| tone | 'default'|'danger' | 'default' |
| 시각적 톤 | ||
| render | (ctx: AlertRenderContext) => ReactNode | — |
| 이 호출에서만 UI를 교체하는 커스텀 렌더 함수. 전역 등록보다 우선순위가 높습니다. | ||
DialogOptions (overlay, trapFocus, scrollLock 등)도 모두 전달할 수 있습니다.
Note
closeOnOverlayClick은 기본값이 false입니다. 배경을 실수로 클릭해 닫히는 것을 방지합니다.
ESC로는 닫을 수 있습니다.
Preview
커스텀 렌더링
render prop
개별 호출에서 UI를 교체합니다.
await alert({
title: '알림',
render: ({ options, close }) => (
<div className="my-alert">
<h2>{options.title}</h2>
<button onClick={close}>확인</button>
</div>
),
})DialogRuntime 전역 등록
앱 전체 기본 Alert 컴포넌트를 등록합니다. 자세한 내용은 Dialog를 참고하세요.
import { DialogRuntime } from '@woon-ui/dialog'
import { MyAlert } from './ui/Alert'
<DialogRuntime components={{ alert: MyAlert }} />MyAlert는 AlertRenderContext를 props로 받는 컴포넌트입니다.
import type { AlertRenderContext } from '@woon-ui/dialog'
export function MyAlert({ options, close }: AlertRenderContext) {
return (
<div>
<h2>{options.title}</h2>
{options.description && <p>{options.description}</p>}
<button onClick={close}>{options.confirmLabel ?? '확인'}</button>
</div>
)
}Tip
렌더 우선순위 (높음 → 낮음): render prop → DialogRuntime components.alert → 내장 기본 UI
AlertRenderContext
render 옵션에 전달되는 컨텍스트입니다.
type AlertRenderContext = {
options: DialogAlertOptions
close: () => void
}options에는 title, description, confirmLabel, tone 등 전달한 옵션이 모두 담깁니다.
스타일
@woon-ui/dialog/css/alert는 alert 전용 data 속성과 base motion을 함께 포함합니다. 버튼 색상 등 특정 값만 바꾸려면 선택자로 override하세요.
[data-woon-alert-confirm] {
background: #6d28d9;
}완전히 교체하려면 @woon-ui/dialog/css/alert import를 제거하고 아래 CSS를 복사해서 수정하세요.
/* ── Alert Base (위치·애니메이션) ────────────────────────────────────────────── */
[data-woon-scroll-lock] {
overflow: hidden;
}
[data-woon-alert-overlay],
[data-woon-alert-content],
[data-woon-alert-content] *,
[data-woon-alert-content] *::before,
[data-woon-alert-content] *::after { box-sizing: border-box; }
[data-woon-alert-overlay] {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.45);
opacity: 0;
transition: opacity 160ms ease-out;
}
[data-woon-alert-overlay][data-entered] {
opacity: 1;
}
[data-woon-alert-overlay][data-state="closed"] {
animation: woon-alert-overlay-out 120ms ease-in forwards;
transition: none;
}
[data-woon-alert-content] {
position: fixed;
top: 50%; left: 50%;
width: min(100%, 28rem);
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-size: 1rem; line-height: 1.5; color: inherit;
opacity: 0;
transform: translate(-50%, calc(-50% + 8px)) scale(0.98);
transition:
opacity 200ms cubic-bezier(0.16, 1, 0.3, 1),
transform 200ms cubic-bezier(0.16, 1, 0.3, 1);
}
[data-woon-alert-content][data-entered] {
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
[data-woon-alert-content][data-state="closed"] {
animation: woon-alert-content-out 140ms ease-in forwards;
transition: none;
}
@keyframes woon-alert-overlay-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes woon-alert-content-out {
from { opacity: 1; transform: translate(-50%, -50%) scale(1); }
to { opacity: 0; transform: translate(-50%, calc(-50% + 6px)) scale(0.98); }
}
/* ── Content 시각 스타일 ── */
[data-woon-alert-content] { padding: 1.25rem 1.5rem; background: #fff; border-radius: 8px; box-shadow: 0 8px 32px rgba(0,0,0,0.12); }
[data-woon-alert-title] { display: block; margin: 0 0 0.35rem; font-size: 1rem; font-weight: 600; }
[data-woon-alert-description] { display: block; margin: 0 0 0.7rem; }
/* ── Alert 버튼 ── */
[data-woon-alert-actions] {
display: flex; justify-content: flex-end; align-items: center;
gap: 0.375rem; margin-top: 1.25rem;
}
[data-woon-alert-confirm] {
-webkit-appearance: none; appearance: none; box-sizing: border-box;
display: inline-flex; align-items: center; justify-content: center;
padding: 0.4375rem 0.875rem; border: none; border-radius: 6px;
font-family: inherit; font-size: 0.875rem; font-weight: 500; line-height: 1.25;
cursor: pointer; transition: opacity 120ms, background 120ms; white-space: nowrap;
background: #0f172a; color: #fff;
}
[data-woon-alert-confirm]:hover { opacity: 0.85; }
[data-woon-alert-confirm][data-tone='danger'] { background: #dc2626; }접근성
role="dialog",aria-modal="true"자동 적용- 포커스 트랩 — Tab이 다이얼로그 내부에서만 순환
- ESC로 닫기 가능
- 닫힐 때 이전 포커스 요소로 복귀