@vaadin/grid
Version:
A free, flexible and high-quality Web Component for showing large amounts of tabular data
689 lines (569 loc) • 15.9 kB
JavaScript
/**
* @license
* Copyright (c) 2016 - 2026 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import '@vaadin/component-base/src/styles/style-props.js';
import { css } from 'lit';
export const gridStyles = css`
/* stylelint-disable no-duplicate-selectors */
:host {
display: flex;
max-width: 100%;
height: 400px;
min-height: var(--_grid-min-height, 0);
flex: 1 1 auto;
align-self: stretch;
position: relative;
box-sizing: border-box;
overflow: hidden;
-webkit-tap-highlight-color: transparent;
background: var(--vaadin-grid-background, var(--vaadin-background-color));
border: var(--vaadin-grid-border-width, 1px) solid var(--_border-color);
cursor: default;
--_border-color: var(--vaadin-grid-border-color, var(--vaadin-border-color-secondary));
--_row-border-width: var(--vaadin-grid-row-border-width, 1px);
--_column-border-width: var(--vaadin-grid-column-border-width, 0px);
--_default-cell-padding: var(--vaadin-padding-block-container) var(--vaadin-padding-inline-container);
border-radius: var(--vaadin-grid-border-radius, var(--vaadin-radius-m));
}
:host([hidden]),
[hidden] {
display: none ;
}
:host([disabled]) {
pointer-events: none;
opacity: 0.7;
}
/* Variant: No outer border */
:host([theme~='no-border']) {
border-width: 0;
border-radius: 0;
}
:host([all-rows-visible]) {
height: auto;
align-self: flex-start;
min-height: auto;
flex-grow: 0;
flex-shrink: 0;
width: 100%;
}
#scroller {
contain: layout;
position: relative;
display: flex;
width: 100%;
min-width: 0;
min-height: 0;
align-self: stretch;
overflow: hidden;
}
#items {
flex-grow: 1;
flex-shrink: 0;
display: block;
position: sticky;
width: 100%;
left: 0;
min-height: 1px;
z-index: 1;
}
#table {
display: flex;
flex-direction: column;
width: 100%;
overflow: auto;
position: relative;
border-radius: inherit;
/* Workaround for a Chrome bug: new stacking context here prevents the scrollbar from getting hidden */
z-index: 0;
}
[no-scrollbars]:is([safari], [firefox]) #table {
overflow: hidden;
}
#header,
#footer {
display: block;
position: sticky;
left: 0;
width: 100%;
z-index: 2;
}
:host([dir='rtl']) #items,
:host([dir='rtl']) #header,
:host([dir='rtl']) #footer {
left: auto;
}
#header {
top: 0;
}
#footer {
bottom: 0;
}
.header-cell {
text-align: inherit;
}
.header-cell,
.reorder-ghost {
font-size: var(--vaadin-grid-header-font-size, 1em);
font-weight: var(--vaadin-grid-header-font-weight, 500);
color: var(--vaadin-grid-header-text-color, var(--vaadin-text-color));
}
.row {
display: flex;
width: 100%;
box-sizing: border-box;
margin: 0;
position: relative;
}
.row:not(:focus-within) {
--_non-focused-row-none: none;
}
.body-row[loading] ::slotted(vaadin-grid-cell-content) {
visibility: hidden;
}
#scroller[column-rendering='lazy'] .body-cell:not(.frozen-cell, .frozen-to-end-cell) {
transform: translateX(var(--_grid-lazy-columns-start));
}
.body-row:empty {
height: 100%;
}
.cell {
padding: 0;
box-sizing: border-box;
}
.cell:where(:not(.details-cell)) {
flex-shrink: 0;
flex-grow: 1;
display: flex;
width: 100%;
position: relative;
align-items: center;
white-space: nowrap;
}
/*
Block borders
::after - row and cell focus outline
::before - header bottom and footer top borders that only appear when scrolling
*/
.row::after {
top: 0;
bottom: calc(var(--_row-border-width) * -1);
}
.body-row {
scroll-margin-bottom: var(--_row-border-width);
}
.cell {
border-block: var(--_row-border-width) var(--_border-color);
border-top-style: solid;
}
.cell::after {
top: calc(var(--_row-border-width) * -1);
bottom: calc(var(--_row-border-width) * -1);
}
/* Block borders / Last header row and first footer row */
.last-header-row::before,
.first-footer-row::before {
position: absolute;
inset-inline: 0;
border-block: var(--_row-border-width) var(--_border-color);
transform: translateX(var(--_grid-horizontal-scroll-position));
}
/* Block borders / First header row */
.first-header-row-cell {
border-top-style: none;
}
.first-header-row-cell::after {
top: 0;
}
/* Block borders / Last header row */
:host([overflow~='top']) .last-header-row::before {
content: '';
bottom: calc(var(--_row-border-width) * -1);
border-bottom-style: solid;
}
/* Block borders / First body row */
#table:not([has-header]) .first-row-cell {
border-top-style: none;
}
#table:not([has-header]) .first-row-cell::after {
top: 0;
}
/* Block borders / Last body row */
.last-row::after {
bottom: 0;
}
.last-row .details-cell,
.last-row-cell:not(.details-opened-row-cell) {
border-bottom-style: solid;
}
/* Block borders / Last body row without footer */
:host([all-rows-visible]),
:host([overflow~='top']),
:host([overflow~='bottom']) {
#table:not([has-footer]) .last-row .details-cell,
#table:not([has-footer]) .last-row-cell:not(.details-opened-row-cell) {
border-bottom-style: none;
&::after {
bottom: 0;
}
}
}
/* Block borders / First footer row */
.first-footer-row::after {
top: calc(var(--_row-border-width) * -1);
}
.first-footer-row-cell {
border-top-style: none;
}
:host([overflow~='bottom']),
:host(:not([overflow~='top'], [all-rows-visible])) #scroller:not([empty-state]) {
.first-footer-row::before {
content: '';
top: calc(var(--_row-border-width) * -1);
border-top-style: solid;
}
}
/* Block borders / Last footer row */
.last-footer-row::after,
.last-footer-row-cell::after {
bottom: 0;
}
/* Inline borders */
.cell {
border-inline: var(--_column-border-width) var(--_border-color);
}
.header-cell:not(.first-column-cell),
.footer-cell:not(.first-column-cell),
.body-cell:not(.first-column-cell) {
border-inline-start-style: solid;
}
.last-frozen-cell:not(.last-column-cell) {
border-inline-end-style: solid;
& + .cell {
border-inline-start-style: none;
}
}
/* Row and cell background */
.row {
background-color: var(--vaadin-grid-row-background-color, var(--vaadin-background-color));
}
.cell {
--_cell-background-image: linear-gradient(
var(--vaadin-grid-cell-background-color, transparent),
var(--vaadin-grid-cell-background-color, transparent)
);
background-color: inherit;
background-repeat: no-repeat;
background-origin: padding-box;
background-image: var(--_cell-background-image);
}
.body-cell {
--_cell-highlight-background-image: linear-gradient(
var(--vaadin-grid-row-highlight-background-color, transparent),
var(--vaadin-grid-row-highlight-background-color, transparent)
);
background-image:
var(--_row-hover-background-image, none), var(--_row-selected-background-image, none),
var(--_cell-highlight-background-image, none), var(--_row-odd-background-image, none),
var(--_cell-background-image, none);
}
.selected-row {
--_row-selected-background-color: var(
--vaadin-grid-row-selected-background-color,
color-mix(in srgb, currentColor 8%, transparent)
);
--_row-selected-background-image: linear-gradient(
var(--_row-selected-background-color),
var(--_row-selected-background-color)
);
}
@media (any-hover: hover) {
.body-row:hover {
--_row-hover-background-color: var(--vaadin-grid-row-hover-background-color, transparent);
--_row-hover-background-image: linear-gradient(
var(--_row-hover-background-color),
var(--_row-hover-background-color)
);
}
}
:host([theme~='row-stripes']) .odd-row {
--_row-odd-background-color: var(
--vaadin-grid-row-odd-background-color,
color-mix(in srgb, var(--vaadin-text-color) 4%, transparent)
);
--_row-odd-background-image: linear-gradient(var(--_row-odd-background-color), var(--_row-odd-background-color));
}
/* Variant: wrap cell contents */
:host([theme~='wrap-cell-content']) .cell:not(.details-cell) {
white-space: normal;
}
/* Raise highlighted rows above others */
.row,
.frozen-cell,
.frozen-to-end-cell {
&:focus,
&:focus-within {
z-index: 3;
}
}
.details-cell {
position: absolute;
bottom: 0;
width: 100%;
}
::slotted(vaadin-grid-cell-content) {
display: block;
overflow: hidden;
text-overflow: var(--vaadin-grid-cell-text-overflow, ellipsis);
padding: var(--vaadin-grid-cell-padding, var(--_default-cell-padding));
flex: 1;
min-height: 1lh;
min-width: 0;
}
.details-cell,
.frozen-cell,
.frozen-to-end-cell {
z-index: 2;
}
/* Empty state */
#scroller:not([empty-state]) #emptystatebody,
#scroller[empty-state] #items {
display: none;
}
#emptystatebody {
display: flex;
position: sticky;
inset: 0;
flex: 1;
overflow: hidden;
}
#emptystaterow {
display: flex;
flex: 1;
}
#emptystatecell {
display: block;
flex: 1;
overflow: auto;
padding: var(--vaadin-grid-cell-padding, var(--_default-cell-padding));
outline: none;
border-block: var(--_row-border-width) var(--_border-color);
}
#table[has-header] #emptystatecell {
border-top-style: solid;
}
#table[has-footer] #emptystatecell {
border-bottom-style: solid;
}
#emptystatecell:focus-visible {
outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
outline-offset: calc(var(--vaadin-focus-ring-width) * -1);
}
/* Reordering styles */
:host([reordering]) ::slotted(vaadin-grid-cell-content),
:host([reordering]) .resize-handle,
#scroller[no-content-pointer-events] ::slotted(vaadin-grid-cell-content) {
pointer-events: none;
}
.reorder-ghost {
visibility: hidden;
position: fixed;
pointer-events: none;
box-shadow:
0 0 0 1px hsla(0deg, 0%, 0%, 0.2),
0 8px 24px -2px hsla(0deg, 0%, 0%, 0.2);
padding: var(--vaadin-grid-cell-padding, var(--_default-cell-padding)) ;
border-radius: 3px;
/* Prevent overflowing the grid in Firefox */
top: 0;
inset-inline-start: 0;
}
:host([reordering]) {
-webkit-user-select: none;
user-select: none;
}
:host([reordering]) .cell {
/* TODO expose a custom property to control this */
--_reorder-curtain-filter: brightness(0.9) contrast(1.1);
}
:host([reordering]) .cell::after {
content: '';
position: absolute;
inset: 0;
z-index: 1;
-webkit-backdrop-filter: var(--_reorder-curtain-filter);
backdrop-filter: var(--_reorder-curtain-filter);
outline: 0;
}
:host([reordering]) .reorder-allowed-cell {
/* TODO expose a custom property to control this */
--_reorder-curtain-filter: brightness(0.94) contrast(1.07);
}
:host([reordering]) .reorder-dragging-cell {
--_reorder-curtain-filter: none;
}
/* Resizing styles */
.resize-handle {
position: absolute;
top: 0;
inset-inline-end: 0;
height: 100%;
cursor: col-resize;
z-index: 1;
opacity: 0;
width: var(--vaadin-focus-ring-width);
background: var(--vaadin-grid-column-resize-handle-color, var(--vaadin-focus-ring-color));
transition: opacity 0.2s;
translate: var(--_column-border-width);
}
.last-column-cell .resize-handle {
translate: 0;
}
:host(:not([reordering])) #scroller:not([column-resizing]) .resize-handle:hover,
.resize-handle:active {
opacity: 1;
transition-delay: 0.15s;
}
.resize-handle::before {
position: absolute;
content: '';
height: 100%;
width: 16px;
translate: calc(-50% + var(--vaadin-focus-ring-width) / 2);
}
:host([dir='rtl']) .resize-handle::before {
translate: calc(50% - var(--vaadin-focus-ring-width) / 2);
}
:is(.last-column-cell, .last-frozen-cell, .first-frozen-to-end-cell) .resize-handle::before {
width: 8px;
translate: 0;
}
:is(.last-column-cell, .last-frozen-cell) .resize-handle::before {
inset-inline-end: 0;
}
.frozen-to-end-cell :is(.resize-handle, .resize-handle::before) {
inset-inline: 0 auto;
}
.frozen-to-end-cell .resize-handle {
translate: calc(var(--_column-border-width) * -1);
}
.first-frozen-to-end-cell {
margin-inline-start: auto;
}
#scroller:is([column-resizing], [range-selecting]) {
-webkit-user-select: none;
user-select: none;
}
/* Focus outline element, also used for d'n'd indication */
:is(.row, .cell)::after {
position: absolute;
z-index: 3;
inset-inline: 0;
pointer-events: none;
outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
outline-offset: calc(var(--vaadin-focus-ring-width) * -1);
}
.row::after {
transform: translateX(var(--_grid-horizontal-scroll-position));
}
.cell:where(:not(.details-cell))::after {
inset-inline: calc(var(--_column-border-width) * -1);
}
.first-column-cell::after {
inset-inline-start: 0;
}
.last-column-cell::after {
inset-inline-end: 0;
}
:host([navigating]) .row:focus,
:host([navigating]) .cell:focus {
outline: 0;
}
.row:focus-visible,
.cell:focus-visible {
outline: 0;
}
.row:focus-visible::after,
.cell:focus-visible::after,
:host([navigating]) .row:focus::after,
:host([navigating]) .cell:focus::after {
content: '';
}
/* Drag'n'drop styles */
:host([dragover]) {
outline: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
outline-offset: calc(var(--vaadin-grid-border-width, 1px) * -1);
}
.row[dragover] {
z-index: 100 ;
}
.row[dragover]::after {
content: '';
}
.dragover-above-row::after {
outline: 0;
border-top: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
}
.dragover-above-row:not(.first-row)::after {
top: calc(var(--vaadin-focus-ring-width) / -2);
}
.dragover-below-row::after {
outline: 0;
border-bottom: var(--vaadin-focus-ring-width) solid var(--vaadin-focus-ring-color);
}
.dragover-below-row:not(.last-row)::after {
bottom: calc(var(--vaadin-focus-ring-width) / -2);
}
.dragstart-row-cell {
border-block: none ;
padding-block: var(--_row-border-width) ;
}
.dragstart-row-cell.last-column-cell {
border-radius: 0 3px 3px 0;
}
.dragstart-row-cell.first-column-cell {
border-radius: 3px 0 0 3px;
}
/* Indicates the number of dragged rows */
/* TODO export custom properties to control styles */
#scroller .dragstart-row:not([dragstart=''])::before {
position: absolute;
left: var(--_grid-drag-start-x);
top: var(--_grid-drag-start-y);
z-index: 100;
content: attr(dragstart);
box-sizing: border-box;
padding: 0.3em;
color: white;
background-color: red;
border-radius: 1em;
font-size: 0.75rem;
line-height: 1;
font-weight: 500;
min-width: 1.6em;
text-align: center;
}
/* Sizer styles */
#sizer {
display: flex;
visibility: hidden;
}
#sizer .details-cell,
#sizer ::slotted(vaadin-grid-cell-content) {
display: none ;
}
#sizer .cell {
display: block;
flex-shrink: 0;
line-height: 0;
height: 0 ;
min-height: 0 ;
max-height: 0 ;
padding: 0 ;
border: none ;
}
#sizer .cell::before {
content: '-';
}
`;