Skip to content

experiment: add dialog base styles and visual tests #9438

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ee6a4ea
experiment: add dialog base styles
jouni Jun 6, 2025
d318895
Update dialog.html
jouni Jun 16, 2025
ea3c2b1
always use part=content as the scroll container
jouni Jun 16, 2025
796f352
set min-width on overlay with no explicit size
jouni Jun 16, 2025
caaca6d
always set bounds when dragging or resizing
jouni Jun 16, 2025
36b30d5
add TODOs for tests
jouni Jun 16, 2025
a198963
reset pointer events for all slotted content
jouni Jun 16, 2025
953ef71
remove corresponding content padding when header and footer are used
jouni Jun 16, 2025
e1585d0
define custom properties for title text styles
jouni Jun 16, 2025
6c3f789
define custom properties for overlay min and max width
jouni Jun 16, 2025
582cc52
conditionally set content part as a scroll container
jouni Jun 16, 2025
6a72a9e
fix lint error
jouni Jun 16, 2025
c4b7273
Fix incorrect import
web-padawan Jun 16, 2025
f28f4bf
fix: remove content top padding when title is present
jouni Jun 17, 2025
76d1b9c
add visual tests for base styles
jouni Jun 17, 2025
eb36a7a
Merge remote-tracking branch 'origin/main' into experiment/base-dialog
vursen Jun 17, 2025
c6c8cf8
revert vaadin-dialog-overlay-core-styles changes
vursen Jun 17, 2025
c002d1c
don't fix size when dragging
jouni Jun 18, 2025
d1a2cc3
test: restore tests
web-padawan Jun 18, 2025
cae8871
test: remove Lumo imports from base styles
web-padawan Jun 18, 2025
7bbe3c7
test: import src version of dialog
web-padawan Jun 18, 2025
4e55c3b
chore: do not publish base styles to npm
web-padawan Jun 18, 2025
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
187 changes: 109 additions & 78 deletions dev/dialog.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,110 +5,141 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Dialog</title>
<script type="module" src="./common.js"></script>

<script type="module">
import './common.js'; // A separate <script type="module"> for this import crashes Safari often
import '@vaadin/dialog';
import '@vaadin/button';
import '@vaadin/checkbox-group';
import '@vaadin/checkbox';
import '@vaadin/dialog';
import '@vaadin/icon';
import '@vaadin/vaadin-lumo-styles/lumo.css';
import '@vaadin/icons';
</script>
</head>

<body>
<vaadin-dialog></vaadin-dialog>
<style>
.content {
display: grid;
gap: 1rem;
justify-items: start;
max-width: 35em;
}

<vaadin-button>Open dialog 1</vaadin-button>
body > .content > div:first-child {
display: none;
}
</style>

<script type="module">
const dialog1 = document.querySelector('vaadin-dialog');
dialog1.headerTitle = 'Title';
dialog1.draggable = true;
dialog1.resizable = true;

dialog1.renderer = (root) => {
if (root.firstChild) {
return;
}

const container = document.createElement('div');
container.style.maxWidth = '40em';
container.style.minWidth = '20em';
root.appendChild(container);

// Second dialog
const dialog2 = document.createElement('vaadin-dialog');
dialog2.renderer = (root2) => {
if (root2.firstChild) {
const defaultOptions = ['title', 'header', 'footer', 'modal', 'resizable', 'draggable'];
document.querySelector('vaadin-checkbox-group').value = defaultOptions;

const openDialog = (e) => {
const dialog = document.createElement('vaadin-dialog');

const scope = e.target.closest('div.content');
const hasTitle = scope.querySelector('[value="title"]').checked;
const hasHeader = scope.querySelector('[value="header"]').checked;
const hasFooter = scope.querySelector('[value="footer"]').checked;
const isModal = scope.querySelector('[value="modal"]').checked;
const hasWidth = scope.querySelector('[value="width"]').checked;
const hasHeight = scope.querySelector('[value="height"]').checked;
const isResizable = scope.querySelector('[value="resizable"]').checked;
const isDraggable = scope.querySelector('[value="draggable"]').checked;

dialog.renderer = (root) => {
if (root.firstChild) {
return;
}

// Close second dialog
const btnClose2 = document.createElement('vaadin-button');
btnClose2.textContent = 'Close dialog 2';
btnClose2.addEventListener('click', () => {
dialog2.opened = false;
});

root2.appendChild(btnClose2);
root.append(scope.cloneNode(true));
root.querySelector('vaadin-checkbox-group').value = defaultOptions;
root.querySelector('vaadin-button').addEventListener('click', openDialog);
};

container.appendChild(dialog2);
if (hasTitle) {
dialog.headerTitle = 'Dialog Title';
}

// Open second dialog
const btnOpen2 = document.createElement('vaadin-button');
btnOpen2.textContent = 'Open dialog 2';
btnOpen2.addEventListener('click', () => {
dialog2.opened = true;
});
if (hasHeader) {
dialog.headerRenderer = (root) => {
if (root.firstChild) {
return;
}
const closeBtn = document.createElement('vaadin-button');
closeBtn.innerHTML = '<vaadin-icon icon="vaadin:close" aria-label="close dialog"></vaadin-icon>';
closeBtn.addEventListener('click', () => {
dialog.opened = false;
});

const text = document.createElement('span');
text.textContent = 'Header content';

root.append(text, closeBtn);
};
}

const text = document.createElement('p');
text.textContent =
'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio laborum optio quo perferendis unde, fuga reprehenderit molestias cum laboriosam ipsa enim voluptatem iusto fugit. Sed, veniam repudiandae consectetur recusandae laudantium.';
text.style.marginTop = '0';
if (hasFooter) {
dialog.footerRenderer = (root) => {
if (root.firstChild) {
return;
}
const button = document.createElement('vaadin-button');
button.textContent = 'Action';
button.setAttribute('theme', 'primary');

container.append(text, btnOpen2);
};
const button2 = document.createElement('vaadin-button');
button2.textContent = 'Action';

dialog1.headerRenderer = (root) => {
if (root.firstChild) {
return;
}
const button = document.createElement('vaadin-button');
button.innerHTML = '<vaadin-icon icon="lumo:cross" aria-label="close dialog"></vaadin-icon>';
button.theme = 'tertiary-inline icon';
button.addEventListener('click', () => {
dialog1.opened = false;
});
const text = document.createElement('span');
text.textContent = 'Footer content';

const text = document.createElement('span');
text.textContent = 'Header content';
root.append(text, button2, button);
};
}

root.append(text, button);
};
if (hasWidth) {
dialog.width = '300px';
}

dialog1.footerRenderer = (root) => {
if (root.firstChild) {
return;
if (hasHeight) {
dialog.height = '280px';
}
const button = document.createElement('vaadin-button');
button.textContent = 'Action';
button.theme = 'primary';

const button2 = document.createElement('vaadin-button');
button2.textContent = 'Action';
dialog.modeless = !isModal;
dialog.resizable = isResizable;
dialog.draggable = isDraggable;

const text = document.createElement('span');
text.textContent = 'Footer content';
document.body.append(dialog);
dialog.opened = true;

root.append(text, button2, button);
dialog.addEventListener('closed', (e) => {
dialog.parentNode.removeChild(dialog);
});
};

// Open first dialog
const btnOpen1 = document.querySelector('vaadin-button');
btnOpen1.addEventListener('click', () => {
dialog1.opened = true;
});
document.querySelector('vaadin-button').addEventListener('click', openDialog);
</script>
</head>

<body>
<div class="content">
<div
>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio laborum optio quo perferendis unde, fuga
reprehenderit molestias cum laboriosam ipsa enim voluptatem iusto fugit. Sed, veniam repudiandae consectetur
recusandae laudantium.</div
>

<vaadin-checkbox-group label="Features" theme="horizontal">
<vaadin-checkbox value="title" label="Title"></vaadin-checkbox>
<vaadin-checkbox value="header" label="Header"></vaadin-checkbox>
<vaadin-checkbox value="footer" label="Footer"></vaadin-checkbox>
<vaadin-checkbox value="modal" label="Modal"></vaadin-checkbox>
<vaadin-checkbox value="width" label="Width (300px)"></vaadin-checkbox>
<vaadin-checkbox value="height" label="Height (280px)"></vaadin-checkbox>
<vaadin-checkbox value="resizable" label="Resizable"></vaadin-checkbox>
<vaadin-checkbox value="draggable" label="Draggable"></vaadin-checkbox>
</vaadin-checkbox-group>

<vaadin-button>Open Dialog</vaadin-button>
</div>
</body>
</html>
2 changes: 2 additions & 0 deletions packages/dialog/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
"lit.d.ts",
"lit.js",
"src",
"!src/styles/*-base-styles.d.ts",
"!src/styles/*-base-styles.js",
"theme",
"vaadin-*.d.ts",
"vaadin-*.js",
Expand Down
10 changes: 10 additions & 0 deletions packages/dialog/src/styles/vaadin-dialog-overlay-base-styles.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* @license
* Copyright (c) 2017 - 2025 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import type { CSSResult } from 'lit';

export const dialogOverlayBase: CSSResult;

export const dialogOverlayStyles: CSSResult;
Loading