Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions docs/content/docs/2.components/modal.md
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,35 @@ slots:
:placeholder{class="h-full"}
::

### Force Mount

Use the `forceMount` prop to force the Modal content to render even when closed. This is useful for SSR when using `portal: false`.

::component-code
---
prettier: true
ignore:
- title
props:
forceMount: true
portal: false
title: 'Modal with force mount'
slots:
default: |

<UButton label="Open" color="neutral" variant="subtle" />

body: |

<Placeholder class="h-48" />
---

:u-button{label="Open" color="neutral" variant="subtle"}

#body
:placeholder{class="h-48"}
::
Comment on lines +363 to +391
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟑 Minor

Fix markdownlint MD007/MD018 in the Force Mount example.

Line 371 (MD007) and Line 389 (MD018) are flagged in this new block. Consider scoping a markdownlint disable to this component-code snippet.

πŸ› οΈ Suggested fix
 ### Force Mount
+
+<!-- markdownlint-disable MD007 MD018 -->
 ::component-code
 ---
 prettier: true
 ignore:
   - title
 props:
   portal:
     to: false
     forceMount: true
   title: 'Modal with force mount'
@@
 `#body`
 :placeholder{class="h-48"}
 ::
+<!-- markdownlint-enable MD007 MD018 -->
🧰 Tools
πŸͺ› markdownlint-cli2 (0.20.0)

371-371: Unordered list indentation
Expected: 0; Actual: 2

(MD007, ul-indent)


389-389: No space after hash on atx style heading

(MD018, no-missing-space-atx)

πŸ€– Prompt for AI Agents
In `@docs/content/docs/2.components/modal.md` around lines 363 - 391, The new
"Force Mount" component-code block triggers markdownlint MD007/MD018; scope a
markdownlint disable to just this snippet by wrapping the component-code block
with per-snippet directives (e.g., add a short markdownlint-disable/enable
comment immediately before and after the component-code block) so lint rules are
suppressed only for this example; look for the ":::component-code" snippet that
contains the portal prop (portal: { to: false, forceMount: true }) and apply the
scoped disable/enable around it to fix MD007/MD018 without affecting other docs.


## Examples

### Control open state
Expand Down
11 changes: 9 additions & 2 deletions src/runtime/components/Modal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ export interface ModalProps extends DialogRootProps {
* @defaultValue true
*/
dismissible?: boolean
/**
* Force the modal content to render even when closed.
* Useful for SSR when using `portal: false`.
* @defaultValue false
*/
forceMount?: boolean
class?: any
ui?: Modal['slots']
}
Expand Down Expand Up @@ -94,7 +100,8 @@ const props = withDefaults(defineProps<ModalProps>(), {
overlay: true,
transition: true,
modal: true,
dismissible: true
dismissible: true,
forceMount: false
})
const emits = defineEmits<ModalEmits>()
const slots = defineSlots<ModalSlots>()
Expand Down Expand Up @@ -221,7 +228,7 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.modal || {})
<slot :open="open" />
</DialogTrigger>

<DialogPortal v-bind="portalProps">
<DialogPortal v-bind="portalProps" :force-mount="forceMount">
Comment thread
maxarias-io marked this conversation as resolved.
Outdated
<template v-if="scrollable">
<DialogOverlay data-slot="overlay" :class="ui.overlay({ class: props.ui?.overlay })">
<ReuseContentTemplate />
Expand Down
1 change: 1 addition & 0 deletions test/components/Modal.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ describe('Modal', () => {
['with closeIcon', { props: { ...props, closeIcon: 'i-lucide-trash' } }],
['with class', { props: { ...props, class: 'bg-elevated' } }],
['with ui', { props: { ...props, ui: { close: 'end-2' } } }],
['with forceMount', { props: { ...props, forceMount: true } }],
// Slots
['with default slot', { props, slots: { default: () => 'Default slot' } }],
['with content slot', { props, slots: { content: () => 'Content slot' } }],
Expand Down
27 changes: 27 additions & 0 deletions test/components/__snapshots__/Modal-vue.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,33 @@ exports[`Modal > renders with footer slot correctly 1`] = `



<!--teleport end-->"
`;

exports[`Modal > renders with forceMount correctly 1`] = `
"<!--v-if-->
<!--teleport start-->



<div data-state="open" style="pointer-events: auto;" data-slot="overlay" class="fixed inset-0 data-[state=open]:animate-[fade-in_200ms_ease-out] data-[state=closed]:animate-[fade-out_200ms_ease-in] bg-elevated/75"></div>
<div data-dismissable-layer="" style="pointer-events: auto;" tabindex="-1" data-slot="content" class="bg-default divide-y divide-default flex flex-col focus:outline-none data-[state=open]:animate-[scale-in_200ms_ease-out] data-[state=closed]:animate-[scale-out_200ms_ease-in] w-[calc(100vw-2rem)] max-w-lg rounded-lg shadow-lg ring ring-default fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 max-h-[calc(100dvh-2rem)] sm:max-h-[calc(100dvh-4rem)] overflow-hidden" id="" role="dialog" aria-describedby="reka-dialog-description-v-1" aria-labelledby="reka-dialog-title-v-0" data-state="open">
<!--v-if-->
<div data-slot="header" class="flex items-center gap-1.5 p-4 sm:px-6 min-h-16">
<div data-slot="wrapper" class="">
<!--v-if-->
<!--v-if-->
</div><button type="button" aria-label="Close" data-slot="base" class="rounded-md font-medium inline-flex items-center disabled:cursor-not-allowed aria-disabled:cursor-not-allowed disabled:opacity-75 aria-disabled:opacity-75 transition-colors text-sm gap-1.5 text-default hover:bg-elevated active:bg-elevated focus:outline-none focus-visible:bg-elevated hover:disabled:bg-transparent dark:hover:disabled:bg-transparent hover:aria-disabled:bg-transparent dark:hover:aria-disabled:bg-transparent p-1.5 absolute top-4 end-4"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" viewBox="0 0 16 16" data-slot="leadingIcon" class="shrink-0 size-5"></svg>
<!--v-if-->
<!--v-if-->
</button>
</div>
<!--v-if-->
<!--v-if-->
</div>



<!--teleport end-->"
`;

Expand Down
27 changes: 27 additions & 0 deletions test/components/__snapshots__/Modal.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,33 @@ exports[`Modal > renders with footer slot correctly 1`] = `



<!--teleport end-->"
`;

exports[`Modal > renders with forceMount correctly 1`] = `
"<!--v-if-->
<!--teleport start-->



<div data-state="open" style="pointer-events: auto;" data-slot="overlay" class="fixed inset-0 data-[state=open]:animate-[fade-in_200ms_ease-out] data-[state=closed]:animate-[fade-out_200ms_ease-in] bg-elevated/75"></div>
<div data-dismissable-layer="" style="pointer-events: auto;" tabindex="-1" data-slot="content" class="bg-default divide-y divide-default flex flex-col focus:outline-none data-[state=open]:animate-[scale-in_200ms_ease-out] data-[state=closed]:animate-[scale-out_200ms_ease-in] w-[calc(100vw-2rem)] max-w-lg rounded-lg shadow-lg ring ring-default fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 max-h-[calc(100dvh-2rem)] sm:max-h-[calc(100dvh-4rem)] overflow-hidden" id="" role="dialog" aria-describedby="reka-dialog-description-v-0-0-1" aria-labelledby="reka-dialog-title-v-0-0-0" data-state="open">
<!--v-if-->
<div data-slot="header" class="flex items-center gap-1.5 p-4 sm:px-6 min-h-16">
<div data-slot="wrapper" class="">
<!--v-if-->
<!--v-if-->
</div><button type="button" aria-label="Close" data-slot="base" class="rounded-md font-medium inline-flex items-center disabled:cursor-not-allowed aria-disabled:cursor-not-allowed disabled:opacity-75 aria-disabled:opacity-75 transition-colors text-sm gap-1.5 text-default hover:bg-elevated active:bg-elevated focus:outline-none focus-visible:bg-elevated hover:disabled:bg-transparent dark:hover:disabled:bg-transparent hover:aria-disabled:bg-transparent dark:hover:aria-disabled:bg-transparent p-1.5 absolute top-4 end-4"><span class="iconify i-lucide:x shrink-0 size-5" aria-hidden="true" data-slot="leadingIcon"></span>
<!--v-if-->
<!--v-if-->
</button>
</div>
<!--v-if-->
<!--v-if-->
</div>



<!--teleport end-->"
`;

Expand Down
Loading