diff --git a/packages/main/cypress/specs/List.cy.tsx b/packages/main/cypress/specs/List.cy.tsx index 46e608d738eb..0775f3d7bb89 100644 --- a/packages/main/cypress/specs/List.cy.tsx +++ b/packages/main/cypress/specs/List.cy.tsx @@ -12,6 +12,7 @@ import ResponsivePopover from "../../src/ResponsivePopover.js"; import Select from "../../src/Select.js"; import Option from "../../src/Option.js"; import CheckBox from "../../src/CheckBox.js"; +import Bar from "../../src/Bar.js"; function getGrowingWithScrollList(length: number, height: string = "100px") { return ( @@ -2516,4 +2517,77 @@ describe("List keyboard drag and drop tests", () => { cy.get("#item9").prev().should("have.id", "item4"); }); +}); + +describe("List sticky header", () => { + it("sticks default header", () => { + cy.mount( +
+ + Item 1 + Item 2 + Item 3 + +
+
+ ); + + cy.get("#scrollContainer") + .as("container"); + + cy.get("[ui5-list]") + .shadow() + .find(".ui5-list-header") + .as("header"); + + cy.get("@header") + .then(($headerBefore) => { + const headerTopBefore = $headerBefore[0].getBoundingClientRect().top; + + cy.get("@container") + .scrollTo(0, 50); + + cy.get("@header") + .should(($headerAfter) => { + const headerTopAfter = $headerAfter[0].getBoundingClientRect().top; + expect(headerTopAfter).to.eq(headerTopBefore); + }); + }); + }); + + it("sticks custom header", () => { + cy.mount( +
+ + + Sticky Header Bar + + Item 1 + Item 2 + Item 3 + +
+
+ ); + + cy.get("#scrollContainer") + .as("container"); + + cy.get("[ui5-bar]") + .as("header"); + + cy.get("@header") + .then(($headerBefore) => { + const headerTopBefore = $headerBefore[0].getBoundingClientRect().top; + + cy.get("@container") + .scrollTo(0, 50); + + cy.get("@header") + .should(($headerAfter) => { + const headerTopAfter = $headerAfter[0].getBoundingClientRect().top; + expect(headerTopAfter).to.eq(headerTopBefore); + }); + }); + }); }); \ No newline at end of file diff --git a/packages/main/src/List.ts b/packages/main/src/List.ts index 92e881c7cf2a..61e86cb021ce 100644 --- a/packages/main/src/List.ts +++ b/packages/main/src/List.ts @@ -396,6 +396,17 @@ class List extends UI5Element { @property({ type: Number }) loadingDelay = 1000; + /** + * Indicates whether the List header is sticky or not. + * If stickyHeader is set to true, then whenever you scroll the content or + * the application, the header of the list will be always visible. + * @default false + * @public + * @since 2.18.0 + */ + @property({ type: Boolean }) + stickyHeader = false; + /** * Defines the accessible name of the component. * @default undefined diff --git a/packages/main/src/ListTemplate.tsx b/packages/main/src/ListTemplate.tsx index ff00c185bc94..c3c0809a1459 100644 --- a/packages/main/src/ListTemplate.tsx +++ b/packages/main/src/ListTemplate.tsx @@ -29,9 +29,7 @@ export default function ListTemplate(this: List) { active={this.showBusyIndicatorOverlay} class="ui5-list-busy-indicator" > - -
- +
{this.header.length > 0 && } @@ -41,41 +39,44 @@ export default function ListTemplate(this: List) { } - {this.hasData && -
- } +
+ - {this.ariaLabelModeText} + {this.hasData && +
+ } -
    - + {this.ariaLabelModeText} - {this.showNoDataText && -
  • -
    - {this.noDataText} -
    -
  • - } -
+
    + - { this.growsWithButton && moreRow.call(this) } + {this.showNoDataText && +
  • +
    + {this.noDataText} +
    +
  • + } +
- {this.footerText && -
{this.footerText}
- } + { this.growsWithButton && moreRow.call(this) } - {this.hasData && -
- } + {this.footerText && +
{this.footerText}
+ } - + {this.hasData && +
+ } + +
diff --git a/packages/main/src/themes/List.css b/packages/main/src/themes/List.css index 748e613f614e..734229e88053 100644 --- a/packages/main/src/themes/List.css +++ b/packages/main/src/themes/List.css @@ -17,7 +17,8 @@ } .ui5-list-root, -.ui5-list-busy-indicator { +.ui5-list-busy-indicator, +.ui5-list-container { width: 100%; height: 100%; position: relative; @@ -111,4 +112,11 @@ :host([growing="Scroll"]) .ui5-list-end-marker { /* Ensure the list-end-marker has a block property to always be stretched and "visible" on the screen */ display: inline-block; +} + +:host([sticky-header]) ::slotted([slot="header"]), +:host([sticky-header]) .ui5-list-header { + position: sticky; + top: 0; + z-index: 100; } \ No newline at end of file diff --git a/packages/main/test/pages/List.html b/packages/main/test/pages/List.html index 2e7b7f36176e..631f663e4395 100644 --- a/packages/main/test/pages/List.html +++ b/packages/main/test/pages/List.html @@ -89,6 +89,46 @@

+

List with sticky header

+ + + Sticky Header Bar + Action + + Item 1 + Item 2 + Item 3 + Item 4 + Item 5 + Item 6 + Item 7 + Item 8 + Item 9 + Item 10 + Item 11 + Item 12 + Item 13 + Item 14 + Item 15 + + + + Item 1 + Item 2 + Item 3 + Item 4 + Item 5 + Item 6 + Item 7 + Item 8 + Item 9 + Item 10 + Item 11 + Item 12 + Item 13 + Item 14 + Item 15 +

List growing="Button" and growing-button-text property used

diff --git a/packages/main/test/pages/styles/List.css b/packages/main/test/pages/styles/List.css index 95b03a98f07c..6b3e184bb73f 100644 --- a/packages/main/test/pages/styles/List.css +++ b/packages/main/test/pages/styles/List.css @@ -23,6 +23,10 @@ justify-content: space-between } +.list6auto { + height: 500px; +} + .largeTopMargin { margin-top: 2rem; } diff --git a/packages/website/docs/_components_pages/main/List/List.mdx b/packages/website/docs/_components_pages/main/List/List.mdx index 7c7a8b8c8a5d..cdcced15d6c2 100644 --- a/packages/website/docs/_components_pages/main/List/List.mdx +++ b/packages/website/docs/_components_pages/main/List/List.mdx @@ -12,6 +12,7 @@ import SeparationTypes from "../../../_samples/main/List/SeparationTypes/Separat import DragAndDrop from "../../../_samples/main/List/DragAndDrop/DragAndDrop.md"; import MultipleDrag from "../../../_samples/main/List/MultipleDrag/MultipleDrag.md"; import WrappingBehavior from "../../../_samples/main/List/WrappingBehavior/WrappingBehavior.md"; +import StickyHeader from "../../../_samples/main/List/StickyHeader/StickyHeader.md"; <%COMPONENT_OVERVIEW%> @@ -75,3 +76,8 @@ This feature improves readability when displaying lengthy content in lists. The `` is intentionally designed as a generic container to provide maximum flexibility. It can be used alongside `ui5-expandable-text` for long text content. + +### Sticky Header +Use the stickyHeader property to keep the header visible during scrolling. + + \ No newline at end of file diff --git a/packages/website/docs/_samples/main/List/StickyHeader/StickyHeader.md b/packages/website/docs/_samples/main/List/StickyHeader/StickyHeader.md new file mode 100644 index 000000000000..17798ecc59ab --- /dev/null +++ b/packages/website/docs/_samples/main/List/StickyHeader/StickyHeader.md @@ -0,0 +1,4 @@ +import html from '!!raw-loader!./sample.html'; +import js from '!!raw-loader!./main.js'; + + diff --git a/packages/website/docs/_samples/main/List/StickyHeader/main.css b/packages/website/docs/_samples/main/List/StickyHeader/main.css new file mode 100644 index 000000000000..82d3ee089e97 --- /dev/null +++ b/packages/website/docs/_samples/main/List/StickyHeader/main.css @@ -0,0 +1,8 @@ +.scrollContainer { + height: 300px; + overflow: auto; +} + +.heading { + margin: 2rem 0 2rem 1rem; +} \ No newline at end of file diff --git a/packages/website/docs/_samples/main/List/StickyHeader/main.js b/packages/website/docs/_samples/main/List/StickyHeader/main.js new file mode 100644 index 000000000000..4cbcf2b9899a --- /dev/null +++ b/packages/website/docs/_samples/main/List/StickyHeader/main.js @@ -0,0 +1,4 @@ +import "@ui5/webcomponents/dist/List.js"; +import "@ui5/webcomponents/dist/ListItemStandard.js"; + +import "@ui5/webcomponents-icons/dist/nutrition-activity.js"; \ No newline at end of file diff --git a/packages/website/docs/_samples/main/List/StickyHeader/sample.html b/packages/website/docs/_samples/main/List/StickyHeader/sample.html new file mode 100644 index 000000000000..a1fa55e10d4b --- /dev/null +++ b/packages/website/docs/_samples/main/List/StickyHeader/sample.html @@ -0,0 +1,46 @@ + + + + + + + + Sticky Header Sample + + + + + + +
+ Scroll down to see the sticky header in action + + Pineapple + Orange + Blueberry + Mango + Apple + Banana + Strawberry + Grape + Papaya + Kiwi + +
+ + + + + + +