diff --git a/docs/components/popup.md b/docs/components/popup.md
index 042fd1bc..73604392 100644
--- a/docs/components/popup.md
+++ b/docs/components/popup.md
@@ -1094,6 +1094,97 @@ const App = () => {
};
```
+### Flip Fallbacks
+
+While using the `flip` attribute, you can customize the placement of the popup when the preferred placement doesn't have room. For this, use `flip-fallback-placements` and `flip-fallback-strategy`.
+
+If the preferred placement doesn't have room, the first suitable placement found in `flip-fallback-placement` will be used. The value of this attribute must be a string including any number of placements separated by a space, e.g. `"right bottom"`.
+
+If no fallback placement works, the final placement will be determined by `flip-fallback-strategy`. This value can be either `initial` (default), where the placement reverts to the position in `placement`, or `best-fit`, where the placement is chosen based on available space.
+
+Scroll the container to see how the popup changes it's fallback placement to prevent clipping.
+
+```html preview
+
+
+
+```
+
+```jsx react
+import { useState } from 'react';
+import { SlPopup, SlSwitch } from '@shoelace-style/shoelace/dist/react';
+
+const css = `
+ .popup-flip-fallbacks .overflow {
+ position: relative;
+ height: 300px;
+ border: solid 2px var(--sl-color-neutral-200);
+ overflow: auto;
+ }
+
+ .popup-flip-fallbacks span[slot='anchor'] {
+ display: inline-block;
+ width: 150px;
+ height: 150px;
+ border: dashed 2px var(--sl-color-neutral-600);
+ margin: 250px 50px;
+ }
+
+ .popup-flip-fallbacks .box {
+ width: 100px;
+ height: 50px;
+ background: var(--sl-color-primary-600);
+ border-radius: var(--sl-border-radius-medium);
+ }
+`;
+
+const App = () => {
+ return (
+ <>
+
+
+
+ >
+ );
+};
+```
+
### Shift
When a popup is longer than its anchor, it risks being clipped by an overflowing container. In this case, use the `shift` attribute to shift the popup along its axis and back into view. You can customize the shift behavior using `shiftBoundary` and `shift-padding`.
diff --git a/docs/resources/changelog.md b/docs/resources/changelog.md
index 000cdd20..540d9ee1 100644
--- a/docs/resources/changelog.md
+++ b/docs/resources/changelog.md
@@ -12,9 +12,12 @@ _During the beta period, these restrictions may be relaxed in the event of a mis
- Added the `sync` attribute to ``
- Changed the `auto-size` attribute of the experimental `` component so it accepts `horizontal`, `vertical`, and `both` instead of a boolean value
+- Changed the `flip-fallback-placement` attribute of the experimental `` component to `flip-fallback-placements`
+- Changed the `flip-fallback-strategy` in the experimental `` component to accept `best-fit` and `initial` instead of `bestFit` and `initialPlacement`
- Fixed a bug in `` that caused the panel to resize horizontally when the trigger is clipped by the viewport [#860](https://github.com/shoelace-style/shoelace/issues/860)
- Fixed a bug in `` where dynamically changing slotted items wouldn't update the tree properly
- Fixed a bug in `` that caused the panel to stack when clicking on the divider in mobile versions of Chrome [#862](https://github.com/shoelace-style/shoelace/issues/862)
+- Fixed a bug in `` that prevented flip fallbacks from working as intended
- Improved single selection in `` so nodes expand and collapse and receive selection when clicking on the label
- Renamed `expanded-icon` and `collapsed-icon` slots to `expand-icon` and `collapse-icon` in the experimental `` and `` components
- Improved RTL support for ``
diff --git a/src/components/popup/popup.ts b/src/components/popup/popup.ts
index 1ecc299c..4597d566 100644
--- a/src/components/popup/popup.ts
+++ b/src/components/popup/popup.ts
@@ -101,7 +101,7 @@ export default class SlPopup extends ShoelaceElement {
/**
* When set, placement of the popup will flip to the opposite site to keep it in view. You can use
- * `flipFallbackPlacement` to further configure how the fallback placement is determined.
+ * `flipFallbackPlacements` to further configure how the fallback placement is determined.
*/
@property({ type: Boolean }) flip = false;
@@ -111,7 +111,7 @@ export default class SlPopup extends ShoelaceElement {
* fallback strategy will be used instead.
* */
@property({
- attribute: 'flip-fallback-placement',
+ attribute: 'flip-fallback-placements',
converter: {
fromAttribute: (value: string) => {
return value
@@ -124,15 +124,14 @@ export default class SlPopup extends ShoelaceElement {
}
}
})
- flipFallbackPlacement = '';
+ flipFallbackPlacements = '';
/**
* When neither the preferred placement nor the fallback placements fit, this value will be used to determine whether
* the popup should be positioned as it was initially preferred or using the best available fit based on available
* space.
*/
- @property({ attribute: 'flip-fallback-strategy' }) flipFallbackStrategy: 'bestFit' | 'initialPlacement' =
- 'initialPlacement';
+ @property({ attribute: 'flip-fallback-strategy' }) flipFallbackStrategy: 'best-fit' | 'initial' = 'initial';
/**
* The flip boundary describes clipping element(s) that overflow will be checked relative to when flipping. By
@@ -304,7 +303,7 @@ export default class SlPopup extends ShoelaceElement {
flip({
boundary: this.flipBoundary,
// @ts-expect-error - We're converting a string attribute to an array here
- fallbackPlacement: this.flipFallbackPlacement,
+ fallbackPlacements: this.flipFallbackPlacements,
fallbackStrategy: this.flipFallbackStrategy,
padding: this.flipPadding
})