diff --git a/dev/aura/aura-view.css b/dev/aura/aura-view.css
index a609225f81a..487ca6bd714 100644
--- a/dev/aura/aura-view.css
+++ b/dev/aura/aura-view.css
@@ -37,7 +37,7 @@
}
}
-:is(vaadin-app-layout[drawer-opened], vaadin-app-layout:has([slot='navbar'] vaadin-drawer-toggle))
+vaadin-app-layout:is([drawer-opened], :has(> [slot='navbar'] vaadin-drawer-toggle))
:is(.aura-view > header, .aura-view-header)
vaadin-drawer-toggle:not([theme~='permanent']),
vaadin-master-detail-layout:not([drawer], [stack]) [slot='detail'].aura-view > header mdl-back-button,
diff --git a/packages/app-layout/src/vaadin-app-layout-mixin.js b/packages/app-layout/src/vaadin-app-layout-mixin.js
index da1c9ceb3d8..cb365a7276c 100644
--- a/packages/app-layout/src/vaadin-app-layout-mixin.js
+++ b/packages/app-layout/src/vaadin-app-layout-mixin.js
@@ -208,6 +208,18 @@ export const AppLayoutMixin = (superclass) =>
window.removeEventListener('keydown', this.__onDrawerKeyDown);
}
+ /** @private */
+ __onNavbarSlotChange() {
+ this._updateTouchOptimizedMode();
+ this.toggleAttribute('has-navbar', !!this.querySelector('[slot="navbar"]'));
+ }
+
+ /** @private */
+ __onDrawerSlotChange() {
+ this._updateDrawerSize();
+ this.toggleAttribute('has-drawer', !!this.querySelector('[slot="drawer"]'));
+ }
+
/**
* A callback for the `primarySection` property observer.
*
diff --git a/packages/app-layout/src/vaadin-app-layout.d.ts b/packages/app-layout/src/vaadin-app-layout.d.ts
index d27edbc7010..376810be055 100644
--- a/packages/app-layout/src/vaadin-app-layout.d.ts
+++ b/packages/app-layout/src/vaadin-app-layout.d.ts
@@ -77,6 +77,13 @@ export type AppLayoutEventMap = AppLayoutCustomEventMap & HTMLElementEventMap;
* `navbar` | Container for the navigation bar
* `drawer` | Container for the drawer area
*
+ * The following state attributes are available for styling:
+ *
+ * Attribute | Description
+ * ---------------|-------------
+ * `has-drawer` | Set when the element has light DOM content in the drawer slot.
+ * `has-navbar` | Set when the element has light DOM content in the navbar slot.
+ *
* See [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.
*
* ### Component's slots
diff --git a/packages/app-layout/src/vaadin-app-layout.js b/packages/app-layout/src/vaadin-app-layout.js
index d443168c3ea..b170e7581d0 100644
--- a/packages/app-layout/src/vaadin-app-layout.js
+++ b/packages/app-layout/src/vaadin-app-layout.js
@@ -59,6 +59,13 @@ import { AppLayoutMixin } from './vaadin-app-layout-mixin.js';
*
* See [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.
*
+ * The following state attributes are available for styling:
+ *
+ * Attribute | Description
+ * ---------------|-------------
+ * `has-drawer` | Set when the element has light DOM content in the drawer slot.
+ * `has-navbar` | Set when the element has light DOM content in the navbar slot.
+ *
* ### Component's slots
*
* The following slots are available to be set
@@ -121,11 +128,11 @@ class AppLayout extends AppLayoutMixin(ElementMixin(ThemableMixin(PolylitMixin(L
render() {
return html`
-
+
-
+
@@ -134,7 +141,7 @@ class AppLayout extends AppLayoutMixin(ElementMixin(ThemableMixin(PolylitMixin(L
-
+
`;
}
diff --git a/packages/app-layout/test/dom/__snapshots__/app-layout.test.snap.js b/packages/app-layout/test/dom/__snapshots__/app-layout.test.snap.js
index b604049d93a..493168d7680 100644
--- a/packages/app-layout/test/dom/__snapshots__/app-layout.test.snap.js
+++ b/packages/app-layout/test/dom/__snapshots__/app-layout.test.snap.js
@@ -1,7 +1,46 @@
/* @web/test-runner snapshot v1 */
export const snapshots = {};
-snapshots["vaadin-app-layout desktop layout shadow default"] =
+snapshots["vaadin-app-layout host default"] =
+`
+
+`;
+/* end snapshot vaadin-app-layout host default */
+
+snapshots["vaadin-app-layout host with drawer"] =
+`
+
+ Drawer Content
+
+
+`;
+/* end snapshot vaadin-app-layout host with drawer */
+
+snapshots["vaadin-app-layout host with navbar"] =
+`
+
+ Navbar Content
+
+
+`;
+/* end snapshot vaadin-app-layout host with navbar */
+
+snapshots["vaadin-app-layout shadow desktop layout default"] =
`
`;
-/* end snapshot vaadin-app-layout desktop layout shadow default */
+/* end snapshot vaadin-app-layout shadow desktop layout default */
-snapshots["vaadin-app-layout desktop layout shadow drawer closed"] =
+snapshots["vaadin-app-layout shadow desktop layout drawer closed"] =
`
`;
-/* end snapshot vaadin-app-layout desktop layout shadow drawer closed */
+/* end snapshot vaadin-app-layout shadow desktop layout drawer closed */
-snapshots["vaadin-app-layout mobile layout shadow default"] =
+snapshots["vaadin-app-layout shadow mobile layout default"] =
`
`;
-/* end snapshot vaadin-app-layout mobile layout shadow default */
+/* end snapshot vaadin-app-layout shadow mobile layout default */
-snapshots["vaadin-app-layout mobile layout shadow drawer opened"] =
+snapshots["vaadin-app-layout shadow mobile layout drawer opened"] =
`
`;
-/* end snapshot vaadin-app-layout mobile layout shadow drawer opened */
+/* end snapshot vaadin-app-layout shadow mobile layout drawer opened */
diff --git a/packages/app-layout/test/dom/app-layout.test.js b/packages/app-layout/test/dom/app-layout.test.js
index db8ed0188d1..1d19824eae6 100644
--- a/packages/app-layout/test/dom/app-layout.test.js
+++ b/packages/app-layout/test/dom/app-layout.test.js
@@ -7,31 +7,55 @@ import '../../vaadin-drawer-toggle.js';
describe('vaadin-app-layout', () => {
let layout;
- async function fixtureLayout() {
- layout = fixtureSync(`
-
-
- Drawer Toggle
-
-
- Page Content
-
- `);
- await nextRender();
- }
+ describe('host', () => {
+ beforeEach(() => {
+ layout = fixtureSync('');
+ });
+
+ it('default', async () => {
+ await expect(layout).dom.to.equalSnapshot();
+ });
- describe('desktop layout', () => {
- before(async () => {
- await setViewport({ width: 1000, height: 1000 });
+ it('with drawer', async () => {
+ const drawer = document.createElement('div');
+ drawer.setAttribute('slot', 'drawer');
+ drawer.textContent = 'Drawer Content';
+ layout.appendChild(drawer);
+ await nextRender();
+ await expect(layout).dom.to.equalSnapshot();
});
+ it('with navbar', async () => {
+ const navbar = document.createElement('div');
+ navbar.setAttribute('slot', 'navbar');
+ navbar.textContent = 'Navbar Content';
+ layout.appendChild(navbar);
+ await nextRender();
+ await expect(layout).dom.to.equalSnapshot();
+ });
+ });
+
+ describe('shadow', () => {
beforeEach(async () => {
- await fixtureLayout();
+ layout = fixtureSync(`
+
+
+ Drawer Toggle
+
+
+ Page Content
+
+ `);
+ await nextRender();
});
- describe('shadow', () => {
+ describe('desktop layout', () => {
+ before(async () => {
+ await setViewport({ width: 1000, height: 1000 });
+ });
+
it('default', async () => {
await expect(layout).shadowDom.to.equalSnapshot();
});
@@ -41,18 +65,12 @@ describe('vaadin-app-layout', () => {
await expect(layout).shadowDom.to.equalSnapshot();
});
});
- });
-
- describe('mobile layout', () => {
- before(async () => {
- await setViewport({ width: 500, height: 500 });
- });
- beforeEach(async () => {
- await fixtureLayout();
- });
+ describe('mobile layout', () => {
+ before(async () => {
+ await setViewport({ width: 500, height: 500 });
+ });
- describe('shadow', () => {
it('default', async () => {
await expect(layout).shadowDom.to.equalSnapshot();
});
diff --git a/packages/aura/src/components/app-layout.css b/packages/aura/src/components/app-layout.css
index 994141f2448..17355dc5b0a 100644
--- a/packages/aura/src/components/app-layout.css
+++ b/packages/aura/src/components/app-layout.css
@@ -94,7 +94,7 @@ vaadin-app-layout > vaadin-master-detail-layout:nth-child(1 of :not([slot])):nth
}
}
-vaadin-app-layout:has([slot='navbar']):has([slot='drawer']) {
+vaadin-app-layout[has-navbar][has-drawer] {
padding-top: var(--_vaadin-app-layout-navbar-offset-size);
&::part(drawer) {
@@ -102,24 +102,21 @@ vaadin-app-layout:has([slot='navbar']):has([slot='drawer']) {
}
}
-vaadin-app-layout:has([slot='drawer']):not([overlay]):not([drawer-opened])
+vaadin-app-layout[has-drawer]:not([overlay]):not([drawer-opened])
> :nth-child(1 of :not([slot])):nth-last-child(1 of :not([slot])) {
border-inline-start-width: min(var(--aura-app-layout-inset), var(--_aura-mdl-border));
}
-vaadin-app-layout:has([slot='navbar']):has([slot='drawer'])[drawer-opened]:not([overlay])
+vaadin-app-layout[has-navbar][has-drawer][drawer-opened]:not([overlay])
> :nth-child(1 of :not([slot])):nth-last-child(1 of :not([slot])) {
border-start-start-radius: var(--aura-app-layout-radius);
}
-vaadin-app-layout:has([slot='navbar']):has([slot='drawer'])
- > :nth-child(1 of :not([slot])):nth-last-child(1 of :not([slot])) {
+vaadin-app-layout[has-navbar][has-drawer] > :nth-child(1 of :not([slot])):nth-last-child(1 of :not([slot])) {
border-top-width: var(--_aura-mdl-border);
}
-vaadin-app-layout:has([slot='navbar'])
- > :is(:not([slot]), [slot='drawer'])
- vaadin-drawer-toggle:not([theme~='permanent']),
-vaadin-app-layout:not(:has([slot='navbar'])) > [slot='drawer'] vaadin-drawer-toggle:not([theme~='permanent']) {
+vaadin-app-layout[has-navbar] > :is(:not([slot]), [slot='drawer']) vaadin-drawer-toggle:not([theme~='permanent']),
+vaadin-app-layout:not([has-navbar]) > [slot='drawer'] vaadin-drawer-toggle:not([theme~='permanent']) {
display: none;
}