Skip to content

refactor!: Base combo box styles #8932

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 7 commits into
base: base-styles
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
89 changes: 62 additions & 27 deletions dev/combo-box.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,77 @@
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Combo box</title>
<title>Combo Box</title>
<script type="module" src="./common.js"></script>

<script type="module">
import '@vaadin/combo-box';
import '@vaadin/combo-box/vaadin-combo-box-light.js';
import '@vaadin/tooltip';
import '@vaadin/combo-box/src/vaadin-lit-combo-box.js';
import '@vaadin/icon/src/vaadin-lit-icon.js';
import '@vaadin/vaadin-lumo-styles/vaadin-iconset.js';
import '@vaadin/icons';
</script>
</head>
<body>
<vaadin-combo-box label="Country">
<vaadin-tooltip slot="tooltip" text="Loading might take time"></vaadin-tooltip>
</vaadin-combo-box>
<section>
<h2>Plain</h2>
<vaadin-combo-box value="Value"></vaadin-combo-box>
<vaadin-combo-box placeholder="Placeholder"></vaadin-combo-box>
</section>

<script type="module">
const comboBox = document.querySelector('vaadin-combo-box');
<section>
<h2>Bells & Whistles</h2>
<vaadin-combo-box
label="Label"
helper-text="Description for this field."
value="Value"
clear-button-visible
error-message="You need to write something in this field."
required>
<vaadin-icon icon="vaadin:search" slot="prefix"></vaadin-icon>
</vaadin-combo-box>
</section>

/*
const res = await fetch('https://demo.vaadin.com/demo-data/1.0/filtered-countries?count=200');
const arr = await res.json();
comboBox.items = arr.result;
*/
<section>
<h2>States</h2>
<vaadin-combo-box
label="Read-only"
helper-text="Description for this field."
value="Value"
clear-button-visible
error-message="You need to write something in this field."
required
readonly>
<vaadin-icon icon="vaadin:search" slot="prefix"></vaadin-icon>
</vaadin-combo-box>

comboBox.dataProvider = async (params, callback) => {
console.log(JSON.stringify(params));
const index = params.page * params.pageSize;
const response = await fetch(
`https://demo.vaadin.com/demo-data/1.0/filtered-countries?index=${index}&count=${params.pageSize}&filter=${params.filter}`,
);
if (response.ok) {
const { result, size } = await response.json();
// Emulate network latency for demo purpose
setTimeout(() => {
callback(result, size);
}, 100);
<vaadin-combo-box
label="Disabled"
helper-text="Description for this field."
value="Value"
clear-button-visible
error-message="You need to write something in this field."
required
disabled>
<vaadin-icon icon="vaadin:search" slot="prefix"></vaadin-icon>
</vaadin-combo-box>
</section>

<script type="module">
document.querySelectorAll('vaadin-combo-box').forEach(comboBox => {
comboBox.dataProvider = async (params, callback) => {
const index = params.page * params.pageSize;
const response = await fetch(
`https://demo.vaadin.com/demo-data/1.0/filtered-countries?index=${index}&count=${params.pageSize}&filter=${params.filter}`,
);
if (response.ok) {
const { result, size } = await response.json();
// Emulate network latency for demo purpose
setTimeout(() => {
callback(result, size);
}, 1000);
}
}
};
});
</script>
</body>
</html>
13 changes: 3 additions & 10 deletions packages/combo-box/src/vaadin-lit-combo-box-item.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
* Copyright (c) 2015 - 2025 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import { css, html, LitElement } from 'lit';
import { html, LitElement } from 'lit';
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
import { itemStyles } from '@vaadin/item/src/vaadin-item-styles.js';
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
import { ComboBoxItemMixin } from './vaadin-combo-box-item-mixin.js';

Expand All @@ -25,15 +26,7 @@ export class ComboBoxItem extends ComboBoxItemMixin(ThemableMixin(DirMixin(Polyl
}

static get styles() {
return css`
:host {
display: block;
}

:host([hidden]) {
display: none;
}
`;
return itemStyles;
}

/** @protected */
Expand Down
33 changes: 32 additions & 1 deletion packages/combo-box/src/vaadin-lit-combo-box-overlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,46 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
import { ComboBoxOverlayMixin } from './vaadin-combo-box-overlay-mixin.js';

const comboBoxOverlayStyles = css`
#overlay {
[part='overlay'] {
position: relative;
width: var(--vaadin-combo-box-overlay-width, var(--_vaadin-combo-box-overlay-default-width, auto));
}

[part~='loader'] {
animation: spin 1s linear infinite;
border: 2px solid;
border-color: var(--_vaadin-background-container-strong) var(--_vaadin-background-container-strong)
var(--_vaadin-color-strong) var(--_vaadin-color-strong);
border-radius: var(--_vaadin-radius-full);
box-sizing: border-box;
display: none;
height: var(--vaadin-icon-size, 1lh);
inset-block-start: calc(var(--vaadin-item-overlay-padding, 4px) + 6px);
inset-inline-end: 8px;
pointer-events: none;
position: absolute;
width: var(--vaadin-icon-size, 1lh);
}

[part='content'] {
display: flex;
flex-direction: column;
height: 100%;
}

:host([loading]) [part~='loader'] {
display: block;
}

:host([loading]) [part~='content'] {
min-height: calc(var(--vaadin-icon-size, 1lh) + 12px + var(--vaadin-item-overlay-padding, 4px) * 2);
}

@keyframes spin {
to {
transform: rotate(360deg);
}
}
`;

/**
Expand Down
14 changes: 4 additions & 10 deletions packages/combo-box/src/vaadin-lit-combo-box-scroller.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,18 @@ export class ComboBoxScroller extends ComboBoxScrollerMixin(PolylitMixin(LitElem
static get styles() {
return css`
:host {
--vaadin-item-checkmark-display: block;
/* Fixes scrollbar disappearing when 'Show scroll bars: Always' enabled in Safari */
box-shadow: 0 0 0 white;
display: block;
min-height: 1px;
overflow: auto;

/* Fixes item background from getting on top of scrollbars on Safari */
transform: translate3d(0, 0, 0);

/* Enable momentum scrolling on iOS */
-webkit-overflow-scrolling: touch;

/* Fixes scrollbar disappearing when 'Show scroll bars: Always' enabled in Safari */
box-shadow: 0 0 0 white;
}

#selector {
border-width: var(--_vaadin-combo-box-items-container-border-width);
border-style: var(--_vaadin-combo-box-items-container-border-style);
border-color: var(--_vaadin-combo-box-items-container-border-color, transparent);
border: var(--vaadin-item-overlay-padding, 4px) solid transparent;
position: relative;
}
`;
Expand Down
8 changes: 8 additions & 0 deletions packages/combo-box/src/vaadin-lit-combo-box.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ class ComboBox extends ComboBoxDataProviderMixin(
:host([opened]) {
pointer-events: auto;
}

[part='toggle-button'] {
cursor: default;
background: var(--_vaadin-color-subtle);
height: var(--vaadin-icon-size, 1lh);
mask-image: var(--_vaadin-icon-chevron-down);
width: var(--vaadin-icon-size, 1lh);
}
`,
];
}
Expand Down
2 changes: 2 additions & 0 deletions packages/component-base/src/style-props.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ addGlobalThemeStyles(
--vaadin-focus-ring-width: 2px;
--vaadin-focus-ring-color: var(--_vaadin-color);

--_vaadin-icon-checkmark: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5"/></svg>');
--_vaadin-icon-chevron-down: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" /></svg>');
--_vaadin-icon-cross: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" /></svg>');
--_vaadin-icon-warn: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /></svg>');
}
Expand Down
51 changes: 51 additions & 0 deletions packages/item/src/vaadin-item-styles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* @license
* Copyright (c) 2017 - 2025 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import '@vaadin/component-base/src/style-props.js';
import { css } from 'lit';

export const itemStyles = css`
@layer base {
:host {
align-items: center;
border-radius: var(--vaadin-item-border-radius, var(--_vaadin-radius-m));
box-sizing: border-box;
cursor: pointer;
display: flex;
gap: var(--vaadin-item-gap, 0 var(--_vaadin-gap-container-inline));
height: var(--vaadin-item-height, auto);
padding: var(--vaadin-item-padding, var(--_vaadin-padding-container));
}

:host([focused]) {
outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
outline-offset: calc(var(--vaadin-focus-ring-width) / -1);
}

:host([disabled]) {
cursor: not-allowed;
opacity: 0.5;
}

:host([hidden]) {
display: none;
Copy link
Member

Choose a reason for hiding this comment

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

Let's use !important for consistency with other components:

Suggested change
display: none;
display: none !important;

}

[part='checkmark'] {
display: var(--vaadin-item-checkmark-display, none);
height: var(--vaadin-icon-size, 1lh);
mask-image: var(--_vaadin-icon-checkmark);
width: var(--vaadin-icon-size, 1lh);
}

:host([selected]) [part='checkmark'] {
background: var(--_vaadin-color-subtle);
}

[part='content'] {
flex: 1;
}
}
`;
20 changes: 10 additions & 10 deletions packages/overlay/src/vaadin-overlay-styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,23 @@ export const overlayStyles = css`
}

[part='overlay'] {
-webkit-overflow-scrolling: touch;
background: var(--vaadin-overlay-background, var(--_vaadin-background));
border: var(--vaadin-overlay-border, 1px solid var(--_vaadin-border-color));
border-radius: var(--vaadin-overlay-border-radius, var(--_vaadin-radius-m));
box-sizing: border-box;
max-width: 100%;
overflow: auto;
overscroll-behavior: contain;
pointer-events: auto;

/* Prevent overflowing the host */
max-width: 100%;
box-sizing: border-box;

-webkit-tap-highlight-color: initial; /* reenable tap highlight inside */
-webkit-tap-highlight-color: initial;
}

[part='backdrop'] {
z-index: -1;
content: '';
background: rgba(0, 0, 0, 0.5);
position: fixed;
content: '';
inset: 0;
pointer-events: auto;
position: fixed;
z-index: -1;
}
`;
7 changes: 7 additions & 0 deletions packages/vaadin-lumo-styles/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ const globals = css`
--vaadin-input-field-value-color: var(--lumo-body-text-color);
--vaadin-input-field-value-font-size: var(--lumo-font-size-m);
--vaadin-input-field-value-font-weight: 500;
/* Item */
--vaadin-item-border-radius: var(--lumo-border-radius-m);
--vaadin-item-gap: 0;
--vaadin-item-height: auto;
--vaadin-item-overlay-padding: var(--lumo-space-xs);
--vaadin-item-padding: 0.5em calc(var(--lumo-space-l) + var(--lumo-border-radius-m) / 4) 0.5em
var(--_lumo-list-box-item-padding-left, calc(var(--lumo-border-radius-m) / 4));
}
`;

Expand Down
Loading