Skip to content
API 风格:

Dialog 대화상자 ​

중요한 정보를 표시하거나 조작을 확인하는 데 사용하는 모달 대화상자 컴포넌트입니다.

기본 사용법 ​

기본 사용법
vue
<script setup lang="ts">
import { ref } from 'vue'
import { LhButton, LhDialog } from '@lh-ui/vue3'

const dialogVisible1 = ref(false)
</script>

<template>
  <!-- 기본 사용법 -->
  <LhButton @click="dialogVisible1 = true">대화상자 열기</LhButton>
  <LhDialog v-model="dialogVisible1" title="알림">
    <p>대화상자 내용입니다</p>
    <template #footer>
      <LhButton @click="dialogVisible1 = false">취소</LhButton>
      <LhButton type="primary" @click="dialogVisible1 = false">확인</LhButton>
    </template>
  </LhDialog>
</template>
vue
<script>
import { LhButton, LhDialog } from '@lh-ui/vue3'

export default {
  components: { LhButton, LhDialog },
  data() {
    return {
      dialogVisible1: false
    }
  }
}
</script>

<template>
  <!-- 기본 사용법 -->
  <LhButton @click="dialogVisible1 = true">대화상자 열기</LhButton>
  <LhDialog v-model="dialogVisible1" title="알림">
    <p>대화상자 내용입니다</p>
    <template #footer>
      <LhButton @click="dialogVisible1 = false">취소</LhButton>
      <LhButton type="primary" @click="dialogVisible1 = false">확인</LhButton>
    </template>
  </LhDialog>
</template>

너비와 높이 커스터마이징 ​

너비 커스터마이징
vue
<script setup lang="ts">
import { ref } from 'vue'
import { LhButton, LhDialog } from '@lh-ui/vue3'

const dialogVisible2 = ref(false)
</script>

<template>
  <!-- 너비와 높이 커스터마이징 -->
  <LhButton @click="dialogVisible2 = true">큰 대화상자 열기</LhButton>
  <LhDialog v-model="dialogVisible2" title="큰 대화상자" width="600px">
    <p>크기를 커스터마이징한 대화상자</p>
    <template #footer>
      <LhButton @click="dialogVisible2 = false">닫기</LhButton>
    </template>
  </LhDialog>
</template>
vue
<script>
import { LhButton, LhDialog } from '@lh-ui/vue3'

export default {
  components: { LhButton, LhDialog },
  data() {
    return {
      dialogVisible2: false
    }
  }
}
</script>

<template>
  <!-- 너비와 높이 커스터마이징 -->
  <LhButton @click="dialogVisible2 = true">큰 대화상자 열기</LhButton>
  <LhDialog v-model="dialogVisible2" title="큰 대화상자" width="600px">
    <p>크기를 커스터마이징한 대화상자</p>
    <template #footer>
      <LhButton @click="dialogVisible2 = false">닫기</LhButton>
    </template>
  </LhDialog>
</template>

드래그 ​

드래그
vue
<script setup lang="ts">
import { ref } from 'vue'
import { LhButton, LhDialog } from '@lh-ui/vue3'

const dialogVisible3 = ref(false)
</script>

<template>
  <!-- 드래그 -->
  <LhButton @click="dialogVisible3 = true">드래그 가능한 대화상자 열기</LhButton>
  <LhDialog v-model="dialogVisible3" title="드래그 가능한 대화상자" draggable>
    <p>제목 표시줄을 드래그하면 이 대화상자를 이동할 수 있습니다.</p>
    <template #footer>
      <LhButton @click="dialogVisible3 = false">닫기</LhButton>
    </template>
  </LhDialog>
</template>
vue
<script>
import { LhButton, LhDialog } from '@lh-ui/vue3'

export default {
  components: { LhButton, LhDialog },
  data() {
    return {
      dialogVisible3: false
    }
  }
}
</script>

<template>
  <!-- 드래그 -->
  <LhButton @click="dialogVisible3 = true">드래그 가능한 대화상자 열기</LhButton>
  <LhDialog v-model="dialogVisible3" title="드래그 가능한 대화상자" draggable>
    <p>제목 표시줄을 드래그하면 이 대화상자를 이동할 수 있습니다.</p>
    <template #footer>
      <LhButton @click="dialogVisible3 = false">닫기</LhButton>
    </template>
  </LhDialog>
</template>

커스텀 테마 ​

대화상자에 커스텀 테마 색상을 적용합니다.

青花瓷(청화백자) 테마 대화상자
vue
<script setup lang="ts">
import { ref } from 'vue'
import { LhConfigProvider, LhButton, LhDialog } from '@lh-ui/vue3'

const dialogThemeVisible = ref(false)
const cerblueTheme = {
  'primary-color': '#2B4C7C',
  'primary-color-hover': '#3D649E',
  'primary-color-bg': '#E8EDF3',
}
</script>

<template>
  <LhConfigProvider :theme-vars="cerblueTheme">
    <!-- 청화백자 테마 -->
    <LhButton @click="dialogThemeVisible = true" type="primary">테마 대화상자 열기</LhButton>
    <LhDialog v-model="dialogThemeVisible" title="청화백자 테마">
      <p>이 대화상자는 청화백자 테마 색상을 사용합니다</p>
      <template #footer>
        <LhButton @click="dialogThemeVisible = false">닫기</LhButton>
      </template>
    </LhDialog>
  </LhConfigProvider>
</template>
vue
<script>
import { LhConfigProvider, LhButton, LhDialog } from '@lh-ui/vue3'

export default {
  components: { LhConfigProvider, LhButton, LhDialog },
  data() {
    return {
      dialogThemeVisible: false,
      cerblueTheme: {
        'primary-color': '#2B4C7C',
        'primary-color-hover': '#3D649E',
        'primary-color-bg': '#E8EDF3',
      },
    }
  },
}
</script>

<template>
  <LhConfigProvider :theme-vars="cerblueTheme">
    <!-- 청화백자 테마 -->
    <LhButton @click="dialogThemeVisible = true" type="primary">테마 대화상자 열기</LhButton>
    <LhDialog v-model="dialogThemeVisible" title="청화백자 테마">
      <p>이 대화상자는 청화백자 테마 색상을 사용합니다</p>
      <template #footer>
        <LhButton @click="dialogThemeVisible = false">닫기</LhButton>
      </template>
    </LhDialog>
  </LhConfigProvider>
</template>

테마에 대한 자세한 내용은 테마 커스터마이징을 참고하세요.

sx 빠른 레이아웃 ​

sx 속성으로 Dialog의 크기와 간격을 빠르게 설정합니다.

sx 빠른 레이아웃
vue
<script setup lang="ts">
import { ref } from 'vue'
import { LhButton, LhDialog } from '@lh-ui/vue3'

const visible = ref(false)
</script>

<template>
  <!-- 대화상자 열기 -->
  <LhButton @click="visible = true">대화상자 열기</LhButton>
  <!-- sx 레이아웃 대화상자 -->
  <LhDialog v-model="visible" title="sx 레이아웃" :sx="{ maxWidth: 400 }">
    <p>최대 너비를 설정했습니다</p>
    <template #footer>
      <LhButton @click="visible = false">취소</LhButton>
    </template>
  </LhDialog>
</template>
vue
<script>
import { LhButton, LhDialog } from '@lh-ui/vue3'

export default {
  components: { LhButton, LhDialog },
  data() {
    return { visible: false }
  },
}
</script>

<template>
  <!-- 대화상자 열기 -->
  <LhButton @click="visible = true">대화상자 열기</LhButton>
  <!-- sx 레이아웃 대화상자 -->
  <LhDialog v-model="visible" title="sx 레이아웃" :sx="{ maxWidth: 400 }">
    <p>최대 너비를 설정했습니다</p>
    <template #footer>
      <LhButton @click="visible = false">취소</LhButton>
    </template>
  </LhDialog>
</template>

국제화 ​

대화상자 글자는 LhConfigProvider와 언어 팩으로 국제화 전환을 구현할 수 있습니다.

국제화
vue
<script setup lang="ts">
import { ref, computed } from 'vue'
import { LhConfigProvider, LhButton, LhDialog, zhCN, enUS } from '@lh-ui/vue3'

const locale = ref('zh-CN')
const i18nVisible = ref(false)
const messages = computed(() => (locale.value === 'zh-CN' ? zhCN : enUS))
</script>

<template>
  <LhConfigProvider :locale="messages">
    <!-- 대화상자 열기 -->
    <LhButton @click="i18nVisible = true">
      {{ locale === 'zh-CN' ? '打开对话框' : 'Open Dialog' }}
    </LhButton>
    <!-- 국제화 대화상자 -->
    <LhDialog v-model="i18nVisible" :title="locale === 'zh-CN' ? '提示' : 'Notice'">
      <p>{{ locale === 'zh-CN' ? '对话框内容' : 'Dialog content' }}</p>
      <template #footer>
        <LhButton @click="i18nVisible = false">
          {{ locale === 'zh-CN' ? '取消' : 'Cancel' }}
        </LhButton>
      </template>
    </LhDialog>
  </LhConfigProvider>
</template>
vue
<script>
import { LhConfigProvider, LhButton, LhDialog, zhCN, enUS } from '@lh-ui/vue3'

export default {
  components: { LhConfigProvider, LhButton, LhDialog },
  data() {
    return {
      locale: 'zh-CN',
      i18nVisible: false,
    }
  },
  computed: {
    messages() {
      return this.locale === 'zh-CN' ? zhCN : enUS
    },
  },
}
</script>

<template>
  <LhConfigProvider :locale="messages">
    <!-- 대화상자 열기 -->
    <LhButton @click="i18nVisible = true">
      {{ locale === 'zh-CN' ? '打开对话框' : 'Open Dialog' }}
    </LhButton>
    <!-- 국제화 대화상자 -->
    <LhDialog v-model="i18nVisible" :title="locale === 'zh-CN' ? '提示' : 'Notice'">
      <p>{{ locale === 'zh-CN' ? '对话框内容' : 'Dialog content' }}</p>
      <template #footer>
        <LhButton @click="i18nVisible = false">
          {{ locale === 'zh-CN' ? '取消' : 'Cancel' }}
        </LhButton>
      </template>
    </LhDialog>
  </LhConfigProvider>
</template>

동작 스위치 ​

닫기 방식 / 스크롤 잠금 / beforeClose
vue
<script setup lang="ts">
import { ref } from 'vue'
import { LhButton, LhDialog } from '@lh-ui/vue3'

const dialogAdv1 = ref(false)
const dialogAdv2 = ref(false)
const dialogAdv3 = ref(false)

function handleAdvBeforeClose(done: () => void) {
  setTimeout(done, 500)
}
</script>

<template>
  <!-- 버튼으로만 닫기 -->
  <LhButton @click="dialogAdv1 = true">버튼으로만 닫기</LhButton>
  <LhDialog
    v-model="dialogAdv1"
    title="버튼으로만 닫기"
    :show-close="false"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
  >
    <p>오른쪽 위 닫기 버튼을 숨기고,오버레이를 클릭하거나 ESC를 눌러도 닫히지 않으며 하단 버튼으로만 닫을 수 있습니다.</p>
    <template #footer>
      <LhButton type="primary" @click="dialogAdv1 = false">확인했습니다</LhButton>
    </template>
  </LhDialog>
  <!-- 스크롤 잠금 안 함 -->
  <LhButton @click="dialogAdv2 = true">스크롤 잠금 안 함</LhButton>
  <LhDialog v-model="dialogAdv2" title="스크롤 잠금 안 함" :lock-scroll="false">
    <p>대화상자가 열려 있을 때도 페이지를 스크롤할 수 있어, 내용이 짧은 가벼운 알림에 적합합니다.</p>
  </LhDialog>
  <!-- 비동기 닫기 -->
  <LhButton @click="dialogAdv3 = true">비동기 닫기</LhButton>
  <LhDialog v-model="dialogAdv3" title="비동기 닫기" :before-close="handleAdvBeforeClose">
    <p>오른쪽 위 닫기 버튼,오버레이 클릭 또는 ESC 누름 후 500ms 지연하고 실제로 닫힙니다(닫기 전 검증 시뮬레이션).</p>
  </LhDialog>
</template>
vue
<script>
import { LhButton, LhDialog } from '@lh-ui/vue3'

export default {
  components: { LhButton, LhDialog },
  data() {
    return {
      dialogAdv1: false,
      dialogAdv2: false,
      dialogAdv3: false,
    }
  },
  methods: {
    handleAdvBeforeClose(done) {
      setTimeout(done, 500)
    },
  },
}
</script>

<template>
  <!-- 버튼으로만 닫기 -->
  <LhButton @click="dialogAdv1 = true">버튼으로만 닫기</LhButton>
  <LhDialog
    v-model="dialogAdv1"
    title="버튼으로만 닫기"
    :show-close="false"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
  >
    <p>오른쪽 위 닫기 버튼을 숨기고,오버레이를 클릭하거나 ESC를 눌러도 닫히지 않으며 하단 버튼으로만 닫을 수 있습니다.</p>
    <template #footer>
      <LhButton type="primary" @click="dialogAdv1 = false">확인했습니다</LhButton>
    </template>
  </LhDialog>
  <!-- 스크롤 잠금 안 함 -->
  <LhButton @click="dialogAdv2 = true">스크롤 잠금 안 함</LhButton>
  <LhDialog v-model="dialogAdv2" title="스크롤 잠금 안 함" :lock-scroll="false">
    <p>대화상자가 열려 있을 때도 페이지를 스크롤할 수 있어, 내용이 짧은 가벼운 알림에 적합합니다.</p>
  </LhDialog>
  <!-- 비동기 닫기 -->
  <LhButton @click="dialogAdv3 = true">비동기 닫기</LhButton>
  <LhDialog v-model="dialogAdv3" title="비동기 닫기" :before-close="handleAdvBeforeClose">
    <p>오른쪽 위 닫기 버튼,오버레이 클릭 또는 ESC 누름 후 500ms 지연하고 실제로 닫힙니다(닫기 전 검증 시뮬레이션).</p>
  </LhDialog>
</template>

위치와 z-index ​

fullscreen / position / top / zIndex / center
vue
<script setup lang="ts">
import { ref } from 'vue'
import { LhButton, LhDialog } from '@lh-ui/vue3'

const dialogAdv4 = ref(false)
const dialogAdv5 = ref(false)
const dialogAdv6 = ref(false)
const dialogAdv7 = ref(false)
</script>

<template>
  <!-- 전체 화면 -->
  <LhButton @click="dialogAdv4 = true">전체 화면</LhButton>
  <LhDialog v-model="dialogAdv4" title="전체 화면 대화상자" fullscreen>
    <p>fullscreen일 때 대화상자가 뷰포트 전체를 채웁니다.</p>
  </LhDialog>
  <!-- 하단 위치 -->
  <LhButton @click="dialogAdv5 = true">하단 위치</LhButton>
  <LhDialog v-model="dialogAdv5" title="하단 위치" position="bottom">
    <p>position이 bottom이면 대화상자가 뷰포트 하단에 가깝게 표시됩니다.</p>
  </LhDialog>
  <!-- 상단 오프셋 + z-index -->
  <LhButton @click="dialogAdv6 = true">상단 오프셋 + z-index</LhButton>
  <LhDialog v-model="dialogAdv6" title="상단 오프셋 + z-index" position="top" top="10vh" :z-index="3000">
    <p>top으로 뷰포트 상단까지의 거리를 조정하고, z-index로 쌓임 순서를 제어합니다.</p>
  </LhDialog>
  <!-- 내용 가운데 정렬 -->
  <LhButton @click="dialogAdv7 = true">내용 가운데 정렬(center)</LhButton>
  <LhDialog v-model="dialogAdv7" title="내용 가운데 정렬" center>
    <p>center는 제목과 내용을 가운데 정렬합니다(구버전 호환, 새 코드는 position 사용을 권장).</p>
    <template #footer>
      <LhButton @click="dialogAdv7 = false">취소</LhButton>
      <LhButton type="primary" @click="dialogAdv7 = false">확인</LhButton>
    </template>
  </LhDialog>
</template>
vue
<script>
import { LhButton, LhDialog } from '@lh-ui/vue3'

export default {
  components: { LhButton, LhDialog },
  data() {
    return {
      dialogAdv4: false,
      dialogAdv5: false,
      dialogAdv6: false,
      dialogAdv7: false,
    }
  },
}
</script>

<template>
  <!-- 전체 화면 -->
  <LhButton @click="dialogAdv4 = true">전체 화면</LhButton>
  <LhDialog v-model="dialogAdv4" title="전체 화면 대화상자" fullscreen>
    <p>fullscreen일 때 대화상자가 뷰포트 전체를 채웁니다.</p>
  </LhDialog>
  <!-- 하단 위치 -->
  <LhButton @click="dialogAdv5 = true">하단 위치</LhButton>
  <LhDialog v-model="dialogAdv5" title="하단 위치" position="bottom">
    <p>position이 bottom이면 대화상자가 뷰포트 하단에 가깝게 표시됩니다.</p>
  </LhDialog>
  <!-- 상단 오프셋 + z-index -->
  <LhButton @click="dialogAdv6 = true">상단 오프셋 + z-index</LhButton>
  <LhDialog v-model="dialogAdv6" title="상단 오프셋 + z-index" position="top" top="10vh" :z-index="3000">
    <p>top으로 뷰포트 상단까지의 거리를 조정하고, z-index로 쌓임 순서를 제어합니다.</p>
  </LhDialog>
  <!-- 내용 가운데 정렬 -->
  <LhButton @click="dialogAdv7 = true">내용 가운데 정렬(center)</LhButton>
  <LhDialog v-model="dialogAdv7" title="내용 가운데 정렬" center>
    <p>center는 제목과 내용을 가운데 정렬합니다(구버전 호환, 새 코드는 position 사용을 권장).</p>
    <template #footer>
      <LhButton @click="dialogAdv7 = false">취소</LhButton>
      <LhButton type="primary" @click="dialogAdv7 = false">확인</LhButton>
    </template>
  </LhDialog>
</template>

Dialog API ​

Props ​

속성설명타입기본값
modelValue대화상자 표시 여부booleanfalse
title대화상자 제목string''
width대화상자 너비string | number'480px'
fullscreen전체 화면 여부booleanfalse
showClose닫기 버튼 표시 여부booleantrue
closeOnClickModal오버레이 클릭 시 닫기 여부booleantrue
closeOnPressEscapeESC 누름 시 닫기 여부booleantrue
draggable드래그 가능 여부booleanfalse
center가운데 정렬 여부(구버전 호환, position 사용을 권장)booleanfalse
position팝업 위치: top / center / bottom"top" | "center" | "bottom"'center'
lockScroll스크롤 잠금 여부booleantrue
beforeClose닫기 전 콜백(done: () => void) => void—
top상단 거리(px)string'15vh'
zIndexz-indexnumber—
themeVars컴포넌트 수준 테마 변수, ConfigProvider 설정을 덮어씀{ [x: string]: string; }—
bgPattern컴포넌트 수준 배경 문양, ConfigProvider 설정을 덮어씀string—
sxsx 빠른 레이아웃 속성LhSxProps—

Events ​

이벤트설명콜백 매개변수
update:modelValue표시 상태 변경(value: boolean)
open열기 애니메이션 종료—
close닫기 애니메이션 종료—
opened대화상자가 완전히 열린 후 발생—
closed대화상자가 완전히 닫힌 후 발생—

Slots ​

슬롯설명
default대화상자 내용
header대화상자 제목 영역
footer대화상자 하단 영역

타입 정의 ​

이 컴포넌트가 외부로 내보내는 TypeScript 타입 구조는 다음과 같습니다(packages/components/dialog/src/types.ts와 @lh-ui/share/core/* 소스에서 자동 추출, 각 항목을 펼쳐 전체 정의를 확인하세요. 속성 설명은 위쪽 Props 표를 참고하세요).

LhDialogProps
ts
/**
 * Dialog 컴포넌트 Props
 */
export interface LhDialogProps {
  /** 표시 여부 */
  modelValue?: boolean
  /** 제목 */
  title?: string
  /** 너비 */
  width?: string | number
  /** 전체 화면 여부 */
  fullscreen?: boolean
  /** 닫기 버튼 표시 여부 */
  showClose?: boolean
  /**오버레이 클릭 시 닫기 여부 */
  closeOnClickModal?: boolean
  /** ESC 누름 시 닫기 여부 */
  closeOnPressEscape?: boolean
  /** 드래그 가능 여부 */
  draggable?: boolean
  /** 가운데 정렬 여부(구버전 호환, position 사용을 권장) */
  center?: boolean
  /** 팝업 위치: top / center / bottom */
  position?: 'top' | 'center' | 'bottom'
  /** 스크롤 잠금 여부 */
  lockScroll?: boolean
  /** 닫기 전 콜백 */
  beforeClose?: (done: () => void) => void
  /** 상단 거리(px) */
  top?: string
  /** z-index */
  zIndex?: number
  /** 컴포넌트 수준 테마 변수, ConfigProvider 설정을 덮어씀 */
  themeVars?: Record<string, string>
  /** 컴포넌트 수준 배경 문양, ConfigProvider 설정을 덮어씀 */
  bgPattern?: string
  /** sx 빠른 레이아웃 속성 */
  sx?: LhSxProps
}

국풍의 아름다움으로 코드의 토대를 세웁니다