Skip to content
13 changes: 7 additions & 6 deletions src/components/ui/sheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,9 @@ export function Sheet({
const defaultSheetIsFullscreen = placement !== "left" && mobilePlacement === "fullscreen";
const defaultSheetIsTopAligned = placement !== "left" && mobilePlacement === "top";
const defaultSheetUsesViewportSize = placement !== "left" && mobileSize === "viewport";
const contentClassTokens = contentClassName?.split(/\s+/) ?? [];
const hasMobileMaxHeight = contentClassTokens.some((token) => /^!?max-h-/.test(token));
const hasSmallScreenMaxHeight = contentClassTokens.some((token) => /^sm:!?max-h-/.test(token));

const sheet = (
<div
Expand Down Expand Up @@ -361,12 +364,10 @@ export function Sheet({
"rounded-t-2xl motion-safe:animate-sheet-up",
defaultSheetUsesViewportSize
? "min-h-[calc(100dvh-2rem)] max-h-[calc(100dvh-1rem)] sm:min-h-0"
: // Skip a default max-h when the caller already caps height via
// contentClassName — cn() does not last-win Tailwind utilities,
// so two unprefixed max-h-* classes race in CSS source order.
/\bmax-h-/.test(contentClassName ?? "")
? undefined
: "max-h-[calc(100dvh-2rem)] sm:max-h-[88dvh]",
: cn(
!hasMobileMaxHeight && "max-h-[calc(100dvh-2rem)]",
!hasSmallScreenMaxHeight && "sm:max-h-[88dvh]",
),
),
),
),
Expand Down
14 changes: 14 additions & 0 deletions tests/sheet.dom.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,20 @@ describe("Sheet stacked-overlay coordination", () => {
vi.useRealTimers();
});

it("keeps caller-provided mobile and small-screen height caps authoritative", () => {
const { getByRole } = render(
<Sheet open onClose={vi.fn()} title="Capped sheet" contentClassName="max-h-[88dvh] sm:max-h-[min(80dvh,36rem)]">
<p>Body</p>
</Sheet>,
);

const classes = getByRole("dialog").classList;
expect(classes).toContain("max-h-[88dvh]");
expect(classes).toContain("sm:max-h-[min(80dvh,36rem)]");
expect(classes).not.toContain("max-h-[calc(100dvh-2rem)]");
expect(classes).not.toContain("sm:max-h-[88dvh]");
});

it("upgrades from the close-button fallback to a late-mounted data-sheet-autofocus target", async () => {
const onClose = vi.fn();
const { rerender } = render(
Expand Down
Loading