MENU
Wwoon

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

옵션

PropTypeDefault
titleReactNode
알림 제목
descriptionReactNode
알림 설명
confirmLabelReactNode'확인'
확인 버튼 텍스트
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 }} />

MyAlertAlertRenderContext를 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로 닫기 가능
  • 닫힐 때 이전 포커스 요소로 복귀