diff --git a/components/collapsible-panel/collapsible-panel.js b/components/collapsible-panel/collapsible-panel.js index 8ace4071b6d..2791d2283f9 100644 --- a/components/collapsible-panel/collapsible-panel.js +++ b/components/collapsible-panel/collapsible-panel.js @@ -173,15 +173,20 @@ class CollapsiblePanel extends SkeletonMixin(FocusMixin(LitElement)) { border-radius: 0; outline-offset: -2px; } + + .d2l-collapsible-panel-top-sentinel { + position: relative; + top: calc(-1 * var(--d2l-page-sticky-top, 0px)); + } .d2l-collapsible-panel.scrolled .d2l-collapsible-panel-header { background-color: var(--d2l-theme-background-color-base); box-shadow: 0 8px 12px -9px rgba(0, 0, 0, 0.3); position: sticky; - top: 0; + top: var(--d2l-page-sticky-top, 0); z-index: 11; /* must be greater greater than list-items with open dropdowns or tooltips */ } .d2l-collapsible-panel.focused.scrolled .d2l-collapsible-panel-header { - top: 2px; + top: calc(var(--d2l-page-sticky-top, 0px) + 2px); } .d2l-collapsible-panel-title { flex: 1; diff --git a/components/page/demo/page-component.js b/components/page/demo/page-component.js index c6c9d7e4428..ec95c7c89ed 100644 --- a/components/page/demo/page-component.js +++ b/components/page/demo/page-component.js @@ -19,6 +19,7 @@ import '../../list/list-controls.js'; import '../../list/list-item.js'; import '../../list/list-item-content.js'; import '../../list/list-item-nav.js'; +import '../../more-less/more-less.js'; import '../../selection/selection-action.js'; import '../../switch/switch-visibility.js'; import '../../switch/switch.js'; @@ -242,153 +243,7 @@ class PageDemo extends LitElement { ${this.#renderDemoMainControls()}

I'm in the default slot of the d2l-page component!

-

List with Sticky Controls (extend-separators)

- - - - - - - -
Introduction to Economics
-
Chapter 1 — Fundamentals
-
Due: May 15, 2026
-
-
- - -
Supply and Demand
-
Chapter 2 — Market Forces
-
Due: May 22, 2026
-
-
- - -
Market Equilibrium
-
Chapter 3 — Price Discovery
-
Due: May 29, 2026
-
-
-
- -

List with Sticky Controls (no extend-separators)

- - - - - - - -
Assignment 1: Research Proposal
-
Weight: 20%
-
Submissions: 14/30
-
-
- - -
Assignment 2: Literature Review
-
Weight: 30%
-
Submissions: 8/30
-
-
- - -
Assignment 3: Final Paper
-
Weight: 50%
-
Submissions: 0/30
-
-
-
- -

Table with Sticky Controls

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CourseEnrolledCompletion RateAvg Grade
Introduction to Biology14587%B+
Advanced Chemistry6279%B
World History9892%A-
-
- -

Sticky Table

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
StudentAssignment 1Assignment 2Final ExamTotal
Alice Johnson92889591.7
Bob Smith85798282.0
Carol Davis78918785.3
David Lee95939092.7
Emily Chen88849187.7
-
+ ${this.#renderTableAndListStickyExamples()}
End of Content
@@ -566,10 +421,227 @@ class PageDemo extends LitElement {
+ + ${this.#renderTableAndListStickyExamples()} +
End of Content
` : nothing; } + + #renderTableAndListStickyExamples() { + return html` +

List with Sticky Controls (extend-separators)

+ + + + + + + +
Introduction to Economics
+
Chapter 1 — Fundamentals
+
Due: May 15, 2026
+
+
+ + +
Supply and Demand
+
Chapter 2 — Market Forces
+
Due: May 22, 2026
+
+
+ + +
Market Equilibrium
+
Chapter 3 — Price Discovery
+
Due: May 29, 2026
+
+
+
+ +

List with Sticky Controls (no extend-separators)

+ + + + + + + +
Assignment 1: Research Proposal
+
Weight: 20%
+
Submissions: 14/30
+
+
+ + +
Assignment 2: Literature Review
+
Weight: 30%
+
Submissions: 8/30
+
+
+ + +
Assignment 3: Final Paper
+
Weight: 50%
+
Submissions: 0/30
+
+
+
+ +

Table with Sticky Controls

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CourseEnrolledCompletion RateAvg Grade
Introduction to Biology14587%B+
Advanced Chemistry6279%B
World History9892%A-
+
+ +

Sticky Table

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StudentAssignment 1Assignment 2Final ExamTotal
Alice Johnson92889591.7
Bob Smith85798282.0
Carol Davis78918785.3
David Lee95939092.7
Emily Chen88849187.7
+
+ +

Sticky Table with Sticky Controls

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DepartmentQ1 RevenueQ2 RevenueQ3 RevenueQ4 RevenueAnnual Total
Engineering$1.2M$1.4M$1.3M$1.5M$5.4M
Marketing$800K$920K$870K$950K$3.5M
Sales$2.1M$2.3M$2.0M$2.5M$8.9M
Support$450K$480K$460K$500K$1.9M
Research$680K$710K$730K$760K$2.9M
+
+ `; + } } customElements.define('d2l-page-demo', PageDemo); diff --git a/components/page/page-main.js b/components/page/page-main.js index ad82de676ea..4c11882fc11 100644 --- a/components/page/page-main.js +++ b/components/page/page-main.js @@ -13,6 +13,13 @@ class PageMain extends PagePanelMixin(LitElement) { .panel-header { top: var(--d2l-page-header-height, 0); } + .panel { + /* stylelint-disable-next-line length-zero-no-unit -- used in calc() by consumers */ + --d2l-page-sticky-top: var(--d2l-page-header-height, 0px); + } + .panel.header-sticky { + --d2l-page-sticky-top: calc(var(--d2l-page-header-height, 0px) + var(--d2l-page-panel-header-height, 0px)); + } `]; render() { diff --git a/components/page/page-panel-mixin.js b/components/page/page-panel-mixin.js index 5efa230b071..ffcddeaaa50 100644 --- a/components/page/page-panel-mixin.js +++ b/components/page/page-panel-mixin.js @@ -27,8 +27,15 @@ export const pagePanelStyles = css` } .panel { + /* stylelint-disable-next-line length-zero-no-unit -- used in calc() by consumers */ + --d2l-page-sticky-top: 0px; padding: 30px; } + + .panel.header-sticky { + --d2l-page-panel-header-height: 70px; + --d2l-page-sticky-top: 70px; + } `; export const PagePanelMixin = superclass => class extends superclass { diff --git a/components/selection/selection-controls.js b/components/selection/selection-controls.js index d164e68ea46..a06912cf432 100644 --- a/components/selection/selection-controls.js +++ b/components/selection/selection-controls.js @@ -50,7 +50,7 @@ export class SelectionControls extends PageableSubscriberMixin(SelectionObserver :host { display: block; position: sticky; - top: 0; + top: var(--d2l-page-sticky-top, 0); } :host([no-sticky]) { position: static; diff --git a/components/table/table-wrapper.js b/components/table/table-wrapper.js index 780249f5348..5a30bf1529c 100644 --- a/components/table/table-wrapper.js +++ b/components/table/table-wrapper.js @@ -241,7 +241,7 @@ export const tableStyles = css` d2l-table-wrapper[sticky-headers][sticky-headers-scroll-wrapper] .d2l-table > thead { display: block; position: sticky; - top: calc(var(--d2l-table-sticky-top, 0px) + var(--d2l-table-border-radius-sticky-offset, 0px)); + top: calc(var(--d2l-page-sticky-top, 0px) + var(--d2l-table-sticky-top, 0px) + var(--d2l-table-border-radius-sticky-offset, 0px)); z-index: 2; } @@ -382,7 +382,7 @@ export class TableWrapper extends PropertyRequiredMixin(PageableMixin(SelectionM } .d2l-sticky-headers-backdrop { position: sticky; - top: calc(var(--d2l-table-sticky-top, 0px) + var(--d2l-table-border-radius)); + top: calc(var(--d2l-page-sticky-top, 0px) + var(--d2l-table-sticky-top, 0px) + var(--d2l-table-border-radius)); width: 100%; z-index: 2; /* Must sit under d2l-table sticky-headers but over sticky columns and regular cells */ } @@ -832,7 +832,8 @@ export class TableWrapper extends PropertyRequiredMixin(PageableMixin(SelectionM const stickyRows = Array.from(this._table.querySelectorAll(SELECTORS.headers)); stickyRows.forEach(r => { - const thTop = hasStickyControls ? `${rowTop}px` : `calc(${rowTop}px + var(--d2l-table-border-radius-sticky-offset, 0px))`; + const borderRadiusOffset = hasStickyControls ? '' : ' + var(--d2l-table-border-radius-sticky-offset, 0px)'; + const thTop = `calc(${rowTop}px + var(--d2l-page-sticky-top, 0px)${borderRadiusOffset})`; const ths = Array.from(r.querySelectorAll('th,td')); ths.forEach(th => th.style.top = thTop);