Skip to content

Add breaking change page for soft hyphen rendering - #13945

Open
dbebawy wants to merge 4 commits into
flutter:mainfrom
dbebawy:hyphens-breaking-change
Open

dbebawy wants to merge 4 commits into
flutter:mainfrom
dbebawy:hyphens-breaking-change

Conversation

@dbebawy

@dbebawy dbebawy commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Description of what this PR is changing or adding, and why:

Adds a breaking change page for flutter/flutter#185152. Soft hyphens (U+00AD) now render as a visible hyphen at line breaks, controlled by a new Hyphens enum, and TextStyle.getParagraphStyle gained a hyphens parameter, which breaks classes that override it. The page covers both, with a migration for each.

Issues fixed by this PR (if any):

None.

PRs or commits this PR depends on (if any):

flutter/flutter#185152, which landed on master on October 3.

Presubmit checklist

  • If you are unwilling, or unable, to sign the CLA, even for a tiny, one-word PR, please file an issue instead of a PR.
  • If this PR is not meant to land until a future stable release, mark it as draft with an explanation.
  • This PR follows the Google Developer Documentation Style Guidelines—for example, it doesn't use i.e. or e.g., and it avoids I and we (first-person pronouns).
  • This PR uses semantic line breaks
    of 80 characters or fewer.

Covers flutter/flutter#185152: soft hyphens (U+00AD) now render at line
breaks, and TextStyle.getParagraphStyle gained a hyphens parameter.
Lines still break in the same places, and hit testing isn't affected.
Note that the web doesn't render soft hyphens yet, and that editable
text and SelectableText can't opt out yet. Use \u00AD escapes in the
code samples so the soft hyphen is visible.
@lamek
lamek self-requested a review October 2, 2026 17:30
mboetger pushed a commit to mboetger/flutter that referenced this pull request Oct 3, 2026
…5152)

## Summary

Adds visible soft hyphen (U+00AD) rendering at line breaks, with a new
`Hyphens` API to opt out. Fixes flutter#18443 on native
platforms; web rendering is tracked in flutter#193506.

A line break that falls on a soft hyphen now renders a visible `-` by
default. A new `Hyphens { manual, hidden }` enum controls this:

- `Hyphens.manual` (default): render a hyphen at the break.
- `Hyphens.hidden`: don't render the hyphen. The soft hyphen is still a
break opportunity.

`hyphens` is a parameter on `Text` / `RichText`, `TextPainter`,
`RenderParagraph`, `TextStyle.getParagraphStyle` and `dart:ui`'s
`ParagraphStyle`, following `textAlign` / `maxLines`. It is not a
`TextStyle` field. Customizing the hyphen string is deferred to flutter#189617.

Design doc:
[flutter.dev/go/soft-hyphens](https://flutter.dev/go/soft-hyphens)
(tracking issue flutter#185154).

## Background

Flutter already breaks lines at U+00AD but never draws the hyphen, so it
behaves like a zero-width space. This change doesn't add any new break
opportunities or change where lines break, but the rendered hyphen makes
its line wider, so it can change `Paragraph.longestLine` and the size of
text laid out with `TextWidthBasis.longestLine`.

The Skia side landed in
[`98daf58d`](google/skia@98daf58d4c) (Skia CL
[1208837](https://skia-review.googlesource.com/c/skia/+/1208837)),
behind `ParagraphStyle::setRenderSoftHyphens(bool)`, which defaults to
`false` for other Skia clients.

## Changes

**Engine**
- `txt::ParagraphStyle` gains a `render_soft_hyphens` flag (default
`true`), which `ParagraphBuilderSkia::TxtToSkia` forwards to
`setRenderSoftHyphens`. The Impeller interop toolkit builds
`txt::ParagraphStyle` too, so it also gets the new default.
- `paragraph_builder.cc` decodes `ParagraphStyle.hyphens` from the FFI
buffer (mask bit 13, slot 7).
- `dart:ui` adds the public `Hyphens` enum and `ParagraphStyle.hyphens`.
The web `dart:ui` accepts and stores the value; web rendering is
flutter#193506.

**Framework**
- `Hyphens` is re-exported from `dart:ui` via
`painting/basic_types.dart`.
- `hyphens` is threaded through `TextStyle.getParagraphStyle` →
`TextPainter` → `RenderParagraph` → `RichText` → `Text` / `Text.rich`,
including the selectable-text path.

## Breaking change

- **API:** adding `hyphens` to `TextStyle.getParagraphStyle` breaks
classes that override it. In practice that's test doubles like the
`_TextStyleProxy` in `test/material/theme_test.dart`, updated here;
material_ui's copy was removed in flutter/packages#12728. The fix is to
add `Hyphens? hyphens` to the override. Migration guide:
flutter/website#13945.
- **Rendering:** text containing U+00AD now shows a hyphen at
soft-hyphen line breaks by default. `Hyphens.hidden` restores the old
look.

## Known limitations

- The hyphen is appended after line breaking, so a line can exceed
`maxWidth` by the hyphen's advance.
- The rendered hyphen isn't included in selection highlight rects
(flutter#189234).
- `EditableText` (and so `TextField`) and `SelectableText` don't take a
`hyphens` parameter yet, so they always render the hyphen.
- Skia also draws the hyphen when a line ends in U+00AD without breaking
there (text ending in U+00AD, or U+00AD right before a space or
newline). The Skia fix is in review ([CL
1378356](https://skia-review.googlesource.com/c/skia/+/1378356)) and
will come in with a Skia roll once it lands.

## Test plan

- [ ] `paragraph_builder_skia_tests.cc::RenderSoftHyphensEnabled`:
`render_soft_hyphens` maps onto Skia in both states
- [ ] `testing/dart/text_test.dart`: `ParagraphStyle.hyphens` encodes
and round-trips in `toString`
- [ ] `testing/dart/paragraph_test.dart`: `ParagraphStyle.hyphens`
reaches the text layout (a line that breaks at a soft hyphen is wider
with `manual` than with `hidden`, and unset matches `manual`), which
covers decoding the setting in the engine
- [ ] `test/widgets/rich_text_test.dart`: `RichText` exposes `hyphens`
via `debugFillProperties`
- [ ] `test/widgets/text_test.dart`: `Text` forwards `hyphens` to
`RenderParagraph` (incl. selectable path); default resolves to
`Hyphens.manual`
- [ ] `test/rendering/paragraph_test.dart`: `RenderParagraph.hyphens`
setter triggers relayout
- [ ] `test/painting/text_painter_test.dart`: `TextPainter.hyphens`
setter; the same width check through `TextPainter`, and changing
`hyphens` after layout changes the width
- [ ] Google internal testing
- [ ] Manual smoke: `Text('inter\u00ADnational')` in a narrow container
shows `inter-` / `national`

@sfshaza2 sfshaza2 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dbebawy, thanks for this! I have a couple minor tweaks.

This change affects apps in two ways.

**Rendering.** Text that contains a soft hyphen now shows a hyphen
wherever a line breaks at it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
wherever a line breaks at it.
wherever a line breaks.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tweaked this slightly so it doesn't read as every line break: "Text now shows a hyphen wherever a line breaks at a soft hyphen."

Comment thread sites/docs/src/content/release/breaking-changes/soft-hyphen-rendering.md Outdated
Say the hyphen shows wherever a line breaks at a soft hyphen, and fill
in the version where the change landed on master.
@dbebawy
dbebawy marked this pull request as ready for review October 5, 2026 18:52
@dbebawy
dbebawy requested a review from a team as a code owner October 5, 2026 18:52

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds a new breaking change document explaining that soft hyphens (U+00AD) now render at line breaks in Flutter, introducing the Hyphens enum and a new hyphens parameter in TextStyle.getParagraphStyle. The review feedback suggests improving the grammar and style guide compliance of a sentence regarding editable text widgets, and updating the migration code example to use the ui. prefix for the Hyphens type to ensure correct compilation.

Comment thread sites/docs/src/content/release/breaking-changes/soft-hyphen-rendering.md Outdated
SelectableText isn't editable, but it's built on EditableText, as
TextField is.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants