From 7bf12519fd2bee08e103fbbfbe4b8d623890c978 Mon Sep 17 00:00:00 2001 From: Rando Leppik Date: Tue, 22 Sep 2026 11:07:25 +0300 Subject: [PATCH 1/3] fix(print): print links instead of hiding them #908 --- .../buttons/button-content/button-content.tsx | 19 ++++++--------- .../components/buttons/button/button.spec.tsx | 5 ++++ src/tedi/components/buttons/button/button.tsx | 23 +++++++++++-------- .../components/navigation/link/link.spec.tsx | 5 ++++ 4 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/tedi/components/buttons/button-content/button-content.tsx b/src/tedi/components/buttons/button-content/button-content.tsx index e4787e82d..70c92d06b 100644 --- a/src/tedi/components/buttons/button-content/button-content.tsx +++ b/src/tedi/components/buttons/button-content/button-content.tsx @@ -5,7 +5,6 @@ import { AllowedHTMLTags, PolymorphicComponentPropWithRef, PolymorphicRef } from import { UnknownType } from '../../../types/commonTypes'; import { Icon, IconWithoutBackgroundProps } from '../../base/icon/icon'; import { Spinner } from '../../loaders/spinner/spinner'; -import { Print } from '../../misc/print/print'; import { Tooltip } from '../../overlays/tooltip'; import { ButtonColor, ButtonType } from '../button/button'; import styles from './button-content.module.scss'; @@ -214,17 +213,13 @@ const InternalButtonContent = forwardRef( ); - return ( - - {showTooltip && isIconOnly && buttonText ? ( - - {buttonElement} - {buttonText} - - ) : ( - buttonElement - )} - + return showTooltip && isIconOnly && buttonText ? ( + + {buttonElement} + {buttonText} + + ) : ( + buttonElement ); } ); diff --git a/src/tedi/components/buttons/button/button.spec.tsx b/src/tedi/components/buttons/button/button.spec.tsx index 03f557355..06789af3a 100644 --- a/src/tedi/components/buttons/button/button.spec.tsx +++ b/src/tedi/components/buttons/button/button.spec.tsx @@ -73,4 +73,9 @@ describe('Button component', () => { fireEvent.click(button); expect(handleClick).toHaveBeenCalledTimes(1); }); + + it('is hidden when printing', () => { + render(); + expect(screen.getByRole('button', { name: 'Save' })).toHaveClass('no-print'); + }); }); diff --git a/src/tedi/components/buttons/button/button.tsx b/src/tedi/components/buttons/button/button.tsx index 116667e93..46675d223 100644 --- a/src/tedi/components/buttons/button/button.tsx +++ b/src/tedi/components/buttons/button/button.tsx @@ -3,6 +3,7 @@ import React, { forwardRef } from 'react'; import { BreakpointSupport, useBreakpointProps } from '../../../helpers'; import { PolymorphicRef } from '../../../helpers/polymorphic/types'; import { UnknownType } from '../../../types/commonTypes'; +import { Print } from '../../misc/print/print'; import ButtonContent, { ButtonContentProps } from '../button-content/button-content'; export type ButtonType = 'primary' | 'secondary' | 'neutral' | 'link'; @@ -42,16 +43,18 @@ const ButtonComponent = forwardRef( const ComponentAs = as || 'button'; return ( - - {children} - + + + {children} + + ); } ); diff --git a/src/tedi/components/navigation/link/link.spec.tsx b/src/tedi/components/navigation/link/link.spec.tsx index 3beda7eef..2b368f1d0 100644 --- a/src/tedi/components/navigation/link/link.spec.tsx +++ b/src/tedi/components/navigation/link/link.spec.tsx @@ -76,4 +76,9 @@ describe('Link component', () => { const link = screen.getByRole('link'); expect(link).not.toHaveClass('tedi-btn--link--icon-standalone'); }); + + it('is printed, unlike buttons', () => { + render(Terms); + expect(screen.getByRole('link', { name: 'Terms' })).not.toHaveClass('no-print'); + }); }); From 40ef6ec9e5c43be5d5131e5a8feef2b33a82af3a Mon Sep 17 00:00:00 2001 From: Rando Leppik Date: Tue, 22 Sep 2026 11:08:01 +0300 Subject: [PATCH 2/3] fix(anchor): print community anchors #908 --- .../button-content/button-content.tsx | 23 +++++----- src/community/components/button/button.tsx | 43 ++++++++++--------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/community/components/button-content/button-content.tsx b/src/community/components/button-content/button-content.tsx index 37f59f1ca..290ab8bed 100644 --- a/src/community/components/button-content/button-content.tsx +++ b/src/community/components/button-content/button-content.tsx @@ -3,7 +3,6 @@ import React, { forwardRef } from 'react'; import { Icon, IconProps } from '../../../tedi/components/base/icon/icon'; import { Spinner } from '../../../tedi/components/loaders/spinner/spinner'; -import Print from '../../../tedi/components/misc/print/print'; import { AllowedHTMLTags, PolymorphicComponentPropWithRef, PolymorphicRef } from '../../helpers/polymorphic/types'; import { IntentionalAny } from '../../types'; import { ButtonColor, ButtonType } from '../button/button'; @@ -168,18 +167,16 @@ const InternalButtonContent = forwardRef( }; return ( - - - {!noStyle ? renderContent() : children} - - + + {!noStyle ? renderContent() : children} + ); } ); diff --git a/src/community/components/button/button.tsx b/src/community/components/button/button.tsx index e7dcb4661..01c1cb2e2 100644 --- a/src/community/components/button/button.tsx +++ b/src/community/components/button/button.tsx @@ -1,5 +1,6 @@ import React, { forwardRef } from 'react'; +import Print from '../../../tedi/components/misc/print/print'; import { PolymorphicRef } from '../../helpers/polymorphic/types'; import { IntentionalAny } from '../../types'; import ButtonContent, { ButtonContentProps } from '../button-content/button-content'; @@ -54,26 +55,28 @@ const InternalButton = forwardRef( const ComponentAs = as || 'button'; return ( - - {children} - + + + {children} + + ); } ); From 1313ac8c6b7e895a00994465a6a2ac30030df3f8 Mon Sep 17 00:00:00 2001 From: Rando Leppik Date: Tue, 22 Sep 2026 11:08:22 +0300 Subject: [PATCH 3/3] docs(print): correct printing documentation #908 --- src/tedi/components/misc/print/printing.mdx | 53 ++++++++++++++------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/src/tedi/components/misc/print/printing.mdx b/src/tedi/components/misc/print/printing.mdx index bfd9e17d8..d19f50cd0 100644 --- a/src/tedi/components/misc/print/printing.mdx +++ b/src/tedi/components/misc/print/printing.mdx @@ -5,19 +5,23 @@ import * as PrintStories from './print.stories'; # Printing in TEDI-Ready -Components and layouts include built-in optimizations for print media (via `@media print` styles). This ensures clean, readable output when users trigger print preview or print to PDF. +TEDI components include print styles for browser printing and saving as PDF. +These styles apply automatically. Use the `` component to customise +print visibility and page breaks. ## Global Print Behaviors (Applied Automatically) -- Text colors and many components are converted to grayscale for better ink economy and readability. -- Most background colors are forced to white (or transparent) to reduce ink usage. +- Links and selected text colours are greyscaled. Individual components also define their own print styles. +- The page uses a light neutral background. Core sets `print-color-adjust: exact` + to ask browsers to preserve the colours defined by the print styles. - Base font size is set to **14px**, with proportional scaling for headings, spacing, and line heights. - Interactive or non-essential elements are **hidden by default** in print: - Buttons - - Links/Anchors (unless overridden) - Header, Footer - - Breadcrumbs - Sidenav / Navigation +- Links and anchors **remain visible when printing**, preserving linked text in the document. +- Breadcrumbs **remain visible when printing** — the trail shows where the printed page came from. + (The older community `Breadcrumbs` still hides itself.) - Expandable components are **expanded by default**: - Accordion - Collapse @@ -27,13 +31,16 @@ Components and layouts include built-in optimizations for print media (via `@med - Review large or multi-column tables individually — consider hiding columns or switching to a simplified print layout when needed. - Some components prevent page breaks internally (e.g. `break-inside: avoid` on table rows, Placeholder content), but most page-break decisions should be made explicitly using the tools below. -**Firefox & Page Breaks Note** -Firefox has supported the modern `break-before`, `break-after`, and `break-inside` properties since version **65** (January 2019). Legacy `page-break-*` properties are aliased for compatibility. -Many fragmentation issues — especially with flex containers and `avoid` values — were resolved around Firefox 122 (late 2023). Complex flexbox layouts may still encounter minor pagination quirks in edge cases. -Always test in Firefox print preview. Relevant historical bugs (mostly fixed): +**Browser support and page breaks** -- [Meta: Flex fragmentation/print issues](https://bugzilla.mozilla.org/show_bug.cgi?id=939897) -- Related fixes: [1744363](https://bugzilla.mozilla.org/show_bug.cgi?id=1744363), [1695475](https://bugzilla.mozilla.org/show_bug.cgi?id=1695475), [1807406](https://bugzilla.mozilla.org/show_bug.cgi?id=1807406) +Modern browsers support CSS page-break controls, but complex layouts can still +paginate differently. Firefox continues to track +[flex layout pagination issues](https://bugzilla.mozilla.org/show_bug.cgi?id=939897). +Check multi-page content in both Firefox and Chrome print preview, especially +long flex layouts and tables. If content is clipped or breaks in an awkward +place, consider simplifying the layout for print or applying break controls to +smaller sections. See [MDN's `break-inside` reference](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/break-inside) +for how break rules are resolved. ## How to Control Print Output @@ -41,19 +48,21 @@ Use these tools — in recommended order: ### 1. Preferred: `` Component -Wrap content to apply print-specific visibility or page-break behavior via cloned `className`. +Wrap elements in `` to control print visibility and page breaks. It adds +print classes to its child elements without rendering an additional DOM element. +Custom child components must pass `className` to their DOM element. ```tsx import { Print } from '@tedi-design-system/react/tedi'; // Hide during print - This toolbar / interactive section disappears when printing +
This toolbar is hidden when printing.
-// Show only during print +// Override no-print on the same element - This message or simplified content is only visible in print preview / on paper +
This content remains visible when printing.
// Control page breaks @@ -70,6 +79,12 @@ import { Print } from '@tedi-design-system/react/tedi'; - `breakBefore` / `breakAfter` / `breakInside`: `'auto'`, `'avoid'`, `'avoid-page'`, `'avoid-column'`, `'avoid-region'` - Full props & stories → [Print component docs](/docs/tedi-ready-components-helpers-print--docs) +**`show` only overrides `no-print` on the same element.** Content inside a +hidden parent remains hidden. It does not hide the element on screen or make it +visible only when printing. + +**`` supports avoiding page breaks, but cannot force a new page.** + ### 2. Conditional Rendering: `usePrint()` Hook + `PrintingProvider` For completely different markup, structure, or logic during print (e.g. no charts, simplified tables, no filters). @@ -94,7 +109,8 @@ function ReportPage({ data }) { } ``` -**Setup (already handled globally):** +**Setup:** Wrap the relevant part of your application in `PrintingProvider` if +it is not already inside one. `usePrint()` requires this provider. ```tsx // In your App.tsx @@ -106,5 +122,6 @@ import { PrintingProvider } from '@tedi-design-system/react/tedi'; ``` - Returns `true` during browser print preview / printing -- Consistent value across all nested components (no race conditions) -- Uses `beforeprint` / `afterprint` events (more reliable than `matchMedia('print')` alone) +- Shares the print state with components inside the provider +- Reads the initial state from `matchMedia('print')` and updates it using + `beforeprint` / `afterprint` events