diff --git a/docs-site/docs/en/frontend/layout-and-navigation.md b/docs-site/docs/en/frontend/layout-and-navigation.md index 2687f050be..95c2cc53a6 100644 --- a/docs-site/docs/en/frontend/layout-and-navigation.md +++ b/docs-site/docs/en/frontend/layout-and-navigation.md @@ -141,7 +141,9 @@ form, a shared document, a short public form. Give that card the From Tailwind's `md` breakpoint (48rem, 768 px at the default font size) the card looks as it does without the class. Below it, the card has no border, radius, shadow, surface color, or padding of its own: the content sits on the -page background inside the page padding, and fields use the full width. Page +page background inside the page padding, and fields use the full width. It +also stops clipping its content, so the focus ring of a full-width field or +button at its edge stays whole, even on a card with `overflow-hidden`. Page layout that changes with `md:` switches at the same width, also when a reader has set a larger default font size. The class works on a `Paper`, on the `paper` utility, and on a card built from utilities. It is one CSS rule on diff --git a/packages/cloud/src/ssr/MinimalLayout.browser.test.ts b/packages/cloud/src/ssr/MinimalLayout.browser.test.ts index 8ce0a4807b..79c8e3a7bb 100644 --- a/packages/cloud/src/ssr/MinimalLayout.browser.test.ts +++ b/packages/cloud/src/ssr/MinimalLayout.browser.test.ts @@ -160,9 +160,9 @@ const cards = { `
${renderToString(() => createComponent(Paper, { as: "section" as const, class: `${surface} flex flex-col gap-4 p-6`, children: field() }), )}
`, - // The Cloud `paper` utility at the top of a form page. + // The Cloud `paper` utility at the top of a form page, clipping its content to the rounded corners like the Core sign-in card. utility: (surface: string) => - `
${renderToString(field)}
`, + `
${renderToString(field)}
`, } as const; const measureCard = async (width: number, card: keyof typeof cards, surface: string, theme: "light" | "dark") => { @@ -194,6 +194,7 @@ const measureCard = async (width: number, card: keyof typeof cards, surface: str shadow: style.boxShadow, background: style.backgroundColor, padding: style.paddingTop, + overflow: style.overflow, }, card: box(section), input: box(document.querySelector(".k2b-input-shell")!), @@ -207,7 +208,8 @@ const measureCard = async (width: number, card: keyof typeof cards, surface: str }; describe("standalone card in a browser", () => { - const flat = { border: "0px", radius: "0px", shadow: "none", background: "rgba(0, 0, 0, 0)", padding: "0px" }; + // A flat card no longer clips, so the outer focus ring of a full-width field at its edge stays whole. + const flat = { border: "0px", radius: "0px", shadow: "none", background: "rgba(0, 0, 0, 0)", padding: "0px", overflow: "visible" }; test("is flat on a phone: the content sits on the page with the page padding", async () => { for (const theme of ["light", "dark"] as const) { diff --git a/packages/cloud/src/styles/utilities-navigation.css b/packages/cloud/src/styles/utilities-navigation.css index 50a1e7d006..5f74b33fb4 100644 --- a/packages/cloud/src/styles/utilities-navigation.css +++ b/packages/cloud/src/styles/utilities-navigation.css @@ -994,7 +994,9 @@ padding or columns with `md:` switches at the same width as the card, also with a larger default font size. `(width < 48rem)` is not: the build lowers it to `max-width: calc(48rem - .001px)`, which Chromium still matches at - 48rem. */ + 48rem. Without a frame there is nothing left to clip, so the card also + stops clipping: its content then reaches the card edge, and a clipping card + would cut the outer focus ring of a full-width button or field. */ @media not all and (min-width: 48rem) { .standalone-card, .k2b-ui .k2b-paper.standalone-card { @@ -1003,6 +1005,7 @@ border-radius: 0; background: transparent; box-shadow: none; + overflow: visible; } }