Skip to content
API 风格:

Dialog ​

LhDialog is used for displaying important information or requiring user interaction within a modal overlay.

Type Definitions ​

The TypeScript type structures exported by this component (auto-extracted from packages/components/dialog/src/types.ts and @lh-ui/share/core/* sources; click each entry to expand; see the Props table above for attribute descriptions):

LhDialogProps
ts

export interface LhDialogProps {

  modelValue?: boolean

  title?: string

  width?: string | number

  fullscreen?: boolean

  showClose?: boolean

  closeOnClickModal?: boolean

  closeOnPressEscape?: boolean

  draggable?: boolean

  center?: boolean

  position?: 'top' | 'center' | 'bottom'

  lockScroll?: boolean

  beforeClose?: (done: () => void) => void

  top?: string

  zIndex?: number

  themeVars?: Record<string, string>

  bgPattern?: string

  sx?: LhSxProps
}

Basic Usage ​

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

const visible = ref(false)
</script>

<template>
  <!-- Basic usage -->
  <LhButton @click="visible = true">Open Dialog</LhButton>
  <LhDialog v-model="visible" title="Dialog Title">
    <p>Dialog content goes here</p>
    <template #footer>
      <LhButton @click="visible = false">Cancel</LhButton>
      <LhButton type="primary">Confirm</LhButton>
    </template>
  </LhDialog>
</template>
vue
<script>
import { LhButton, LhDialog } from '@lh-ui/vue3'

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

<template>
  <!-- Basic usage -->
  <LhButton @click="visible = true">Open Dialog</LhButton>
  <LhDialog v-model="visible" title="Dialog Title">
    <p>Dialog content goes here</p>
    <template #footer>
      <LhButton @click="visible = false">Cancel</LhButton>
      <LhButton type="primary">Confirm</LhButton>
    </template>
  </LhDialog>
</template>

Custom Width ​

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

const visible2 = ref(false)
</script>

<template>
  <!-- Custom width -->
  <LhButton @click="visible2 = true">Open Wide Dialog</LhButton>
  <LhDialog v-model="visible2" title="Wide Dialog" width="600px">
    <p>Dialog with custom width</p>
  </LhDialog>
</template>
vue
<script>
import { LhButton, LhDialog } from '@lh-ui/vue3'

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

<template>
  <!-- Custom width -->
  <LhButton @click="visible2 = true">Open Wide Dialog</LhButton>
  <LhDialog v-model="visible2" title="Wide Dialog" width="600px">
    <p>Custom width dialog</p>
  </LhDialog>
</template>

Draggable ​

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

const visible3 = ref(false)
</script>

<template>
  <!-- Draggable -->
  <LhButton @click="visible3 = true">Open Draggable Dialog</LhButton>
  <LhDialog v-model="visible3" title="Draggable" draggable>
    <p>Drag the title bar to move this dialog</p>
  </LhDialog>
</template>
vue
<script>
import { LhButton, LhDialog } from '@lh-ui/vue3'

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

<template>
  <!-- Draggable -->
  <LhButton @click="visible3 = true">Open Draggable Dialog</LhButton>
  <LhDialog v-model="visible3" title="Draggable" draggable>
    <p>Drag the title bar to move this dialog</p>
  </LhDialog>
</template>

sx Quick Layout ​

Use the sx prop to quickly set spacing and sizing on the dialog root, without writing extra CSS.

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

const visible4 = ref(false)
</script>

<template>
  <!-- sx max width -->
  <LhButton @click="visible4 = true">Open Narrow Dialog</LhButton>
  <LhDialog v-model="visible4" title="Narrow" :sx="{ maxWidth: 360 }">
    <p>This dialog is capped at 360px wide</p>
  </LhDialog>
</template>
vue
<script>
import { LhButton, LhDialog } from '@lh-ui/vue3'

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

<template>
  <!-- sx max width -->
  <LhButton @click="visible4 = true">Open Narrow Dialog</LhButton>
  <LhDialog v-model="visible4" title="Narrow" :sx="{ maxWidth: 360 }">
    <p>This dialog is capped at 360px wide</p>
  </LhDialog>
</template>

sx is scaled on an 8px base. See sx Quick Layout for the full API.

Behavior Options ​

Close behavior / scroll lock / beforeClose
vue
<script setup lang="ts">
import { ref } from 'vue'
import { LhButton, LhDialog } from '@lh-ui/vue3'

const advVisible1 = ref(false)
const advVisible2 = ref(false)
const advVisible3 = ref(false)

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

<template>
  <!-- Close by button only -->
  <LhButton @click="advVisible1 = true">Close by button only</LhButton>
  <LhDialog
    v-model="advVisible1"
    title="Close by button only"
    :show-close="false"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
  >
    <p>The corner close button is hidden; clicking the overlay or pressing Escape will not close it — only the footer button does.</p>
    <template #footer>
      <LhButton type="primary" @click="advVisible1 = false">Got it</LhButton>
    </template>
  </LhDialog>
  <!-- No scroll lock -->
  <LhButton @click="advVisible2 = true">No scroll lock</LhButton>
  <LhDialog v-model="advVisible2" title="No scroll lock" :lock-scroll="false">
    <p>The page keeps scrolling while this dialog is open — handy for short, lightweight notices.</p>
  </LhDialog>
  <!-- Async close -->
  <LhButton @click="advVisible3 = true">Async close</LhButton>
  <LhDialog v-model="advVisible3" title="Async close" :before-close="handleAdvBeforeClose">
    <p>After the close button, overlay click, or Escape, the dialog actually closes 500ms later (simulating a pre-close check).</p>
  </LhDialog>
</template>
vue
<script>
import { LhButton, LhDialog } from '@lh-ui/vue3'

export default {
  components: { LhButton, LhDialog },
  data() {
    return {
      advVisible1: false,
      advVisible2: false,
      advVisible3: false,
    }
  },
  methods: {
    handleAdvBeforeClose(done) {
      setTimeout(done, 500)
    },
  },
}
</script>

<template>
  <!-- Close by button only -->
  <LhButton @click="advVisible1 = true">Close by button only</LhButton>
  <LhDialog
    v-model="advVisible1"
    title="Close by button only"
    :show-close="false"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
  >
    <p>The corner close button is hidden; clicking the overlay or pressing Escape will not close it — only the footer button does.</p>
    <template #footer>
      <LhButton type="primary" @click="advVisible1 = false">Got it</LhButton>
    </template>
  </LhDialog>
  <!-- No scroll lock -->
  <LhButton @click="advVisible2 = true">No scroll lock</LhButton>
  <LhDialog v-model="advVisible2" title="No scroll lock" :lock-scroll="false">
    <p>The page keeps scrolling while this dialog is open — handy for short, lightweight notices.</p>
  </LhDialog>
  <!-- Async close -->
  <LhButton @click="advVisible3 = true">Async close</LhButton>
  <LhDialog v-model="advVisible3" title="Async close" :before-close="handleAdvBeforeClose">
    <p>After the close button, overlay click, or Escape, the dialog actually closes 500ms later (simulating a pre-close check).</p>
  </LhDialog>
</template>

Position and Stacking ​

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

const advVisible4 = ref(false)
const advVisible5 = ref(false)
const advVisible6 = ref(false)
const advVisible7 = ref(false)
</script>

<template>
  <!-- Fullscreen -->
  <LhButton @click="advVisible4 = true">Fullscreen</LhButton>
  <LhDialog v-model="advVisible4" title="Fullscreen Dialog" fullscreen>
    <p>With fullscreen the dialog covers the whole viewport.</p>
  </LhDialog>
  <!-- Bottom position -->
  <LhButton @click="advVisible5 = true">Bottom position</LhButton>
  <LhDialog v-model="advVisible5" title="Bottom Position" position="bottom">
    <p>With position set to bottom, the dialog sits near the bottom of the viewport.</p>
  </LhDialog>
  <!-- Top offset + z-index -->
  <LhButton @click="advVisible6 = true">Top offset + z-index</LhButton>
  <LhDialog v-model="advVisible6" title="Top Offset + Stacking" position="top" top="10vh" :z-index="3000">
    <p>The top prop sets the distance from the viewport top; z-index controls the stacking order.</p>
  </LhDialog>
  <!-- Centered content -->
  <LhButton @click="advVisible7 = true">Centered content</LhButton>
  <LhDialog v-model="advVisible7" title="Centered Content" center>
    <p>center centers the title and content (legacy; prefer position in new code).</p>
    <template #footer>
      <LhButton @click="advVisible7 = false">Cancel</LhButton>
      <LhButton type="primary" @click="advVisible7 = false">Confirm</LhButton>
    </template>
  </LhDialog>
</template>
vue
<script>
import { LhButton, LhDialog } from '@lh-ui/vue3'

export default {
  components: { LhButton, LhDialog },
  data() {
    return {
      advVisible4: false,
      advVisible5: false,
      advVisible6: false,
      advVisible7: false,
    }
  },
}
</script>

<template>
  <!-- Fullscreen -->
  <LhButton @click="advVisible4 = true">Fullscreen</LhButton>
  <LhDialog v-model="advVisible4" title="Fullscreen Dialog" fullscreen>
    <p>With fullscreen the dialog covers the whole viewport.</p>
  </LhDialog>
  <!-- Bottom position -->
  <LhButton @click="advVisible5 = true">Bottom position</LhButton>
  <LhDialog v-model="advVisible5" title="Bottom Position" position="bottom">
    <p>With position set to bottom, the dialog sits near the bottom of the viewport.</p>
  </LhDialog>
  <!-- Top offset + z-index -->
  <LhButton @click="advVisible6 = true">Top offset + z-index</LhButton>
  <LhDialog v-model="advVisible6" title="Top Offset + Stacking" position="top" top="10vh" :z-index="3000">
    <p>The top prop sets the distance from the viewport top; z-index controls the stacking order.</p>
  </LhDialog>
  <!-- Centered content -->
  <LhButton @click="advVisible7 = true">Centered content</LhButton>
  <LhDialog v-model="advVisible7" title="Centered Content" center>
    <p>center centers the title and content (legacy; prefer position in new code).</p>
    <template #footer>
      <LhButton @click="advVisible7 = false">Cancel</LhButton>
      <LhButton type="primary" @click="advVisible7 = false">Confirm</LhButton>
    </template>
  </LhDialog>
</template>

Props ​

PropDescriptionTypeDefault
modelValueVisibilitybooleanfalse
titleDialog titlestring''
widthDialog widthstring | number'480px'
fullscreenWhether fullscreenbooleanfalse
showCloseShow close buttonbooleantrue
closeOnClickModalClose on overlay clickbooleantrue
closeOnPressEscapeClose on Escape keybooleantrue
draggableEnable draggingbooleanfalse
centerWhether to center the dialog (legacy; prefer position)booleanfalse
positionDialog position: top / center / bottom"top" | "center" | "bottom"'center'
lockScrollWhether to lock scrollingbooleantrue
beforeCloseCallback before close(done: () => void) => void—
topDistance from the top (px)string'15vh'
zIndexz-indexnumber—
themeVarsComponent-level theme variables, overriding ConfigProvider configuration{ [x: string]: string; }—
bgPatternComponent-level background pattern, overriding ConfigProvider configurationstring—
sxsx quick-layout propsLhSxProps—

Events ​

EventDescriptionCallback
update:modelValueVisibility change(value: boolean) => void
openDialog opened() => void
closeDialog closed() => void
openedEmitted after the dialog is fully opened() => void
closedEmitted after the dialog is fully closed() => void

Slots ​

SlotDescription
defaultDialog body content
titleCustom title
footerFooter area

Beauty of tradition, foundation of code