Summary
On macOS, a TextField that is not being edited draws its text 2pt higher than a stock AppKit NSTextField. When the field gains focus, AppKit's field editor draws the text at the stock position, so the text jumps down 2pt. A Text label is not affected.
Measured
Borderless fields, 40pt tall, 16pt Helvetica. Distance from the field's top edge to the top of the "H":
|
Not editing |
Editing |
Stock AppKit NSTextField |
3.5pt |
3.5pt |
Perry TextField |
1.5pt |
3.5pt |
A Perry Text label and a stock NSTextField(labelWithString:) both put the "H" 3.5pt below the frame's top, so labels match.
The offset shows with zero insets, so it does not come from setPadding. Perry replaces each field's cell with PerryInsetTextFieldCell (install_text_field_cell in crates/perry-ui-macos/src/widgets/padding.rs), and the difference is in how that cell draws text when the field is not editing.
Repro
import { App, TextField, VStack, textSetFontFamily, textfieldFocus, textfieldSetBackgroundColor, textfieldSetBorderless, textfieldSetFontSize, textfieldSetString, textfieldSetTextColor, widgetSetBackgroundColor, widgetSetHeight } from "perry/ui"
function field(text: string) {
const f = TextField("", () => {})
textfieldSetBorderless(f, 1)
textfieldSetFontSize(f, 16)
textSetFontFamily(f, "Helvetica")
textfieldSetBackgroundColor(f, 1, 1, 0.7, 1)
textfieldSetTextColor(f, 0, 0, 0, 1)
widgetSetHeight(f, 40)
textfieldSetString(f, text)
return f
}
const first = field("Hxg first")
const second = field("Hxg second")
const body = VStack(40, [first, second])
widgetSetBackgroundColor(body, 1, 1, 1, 1)
App({ title: "probe", width: 400, height: 200, windowState: "normal", body })
The first field opens as the first responder, so it draws through the field editor. Its text sits 2pt lower in its box than the second field's text. Click into the second field and its text drops 2pt.
For the stock comparison, the same two fields built in Swift (NSTextField(frame:), isBezeled = false, isBordered = false, 16pt Helvetica, 40pt tall) draw the "H" 3.5pt below the top whether or not the field is editing.
Expected
A TextField draws its text in the same place whether or not it is editing, matching a stock NSTextField.
Perry: main at 4a1b788 with the sRGB change from #11613 applied, which touches only colour creation. macOS 26.6.2.
Summary
On macOS, a
TextFieldthat is not being edited draws its text 2pt higher than a stock AppKitNSTextField. When the field gains focus, AppKit's field editor draws the text at the stock position, so the text jumps down 2pt. ATextlabel is not affected.Measured
Borderless fields, 40pt tall, 16pt Helvetica. Distance from the field's top edge to the top of the "H":
NSTextFieldTextFieldA Perry
Textlabel and a stockNSTextField(labelWithString:)both put the "H" 3.5pt below the frame's top, so labels match.The offset shows with zero insets, so it does not come from
setPadding. Perry replaces each field's cell withPerryInsetTextFieldCell(install_text_field_cellincrates/perry-ui-macos/src/widgets/padding.rs), and the difference is in how that cell draws text when the field is not editing.Repro
The first field opens as the first responder, so it draws through the field editor. Its text sits 2pt lower in its box than the second field's text. Click into the second field and its text drops 2pt.
For the stock comparison, the same two fields built in Swift (
NSTextField(frame:),isBezeled = false,isBordered = false, 16pt Helvetica, 40pt tall) draw the "H" 3.5pt below the top whether or not the field is editing.Expected
A
TextFielddraws its text in the same place whether or not it is editing, matching a stockNSTextField.Perry: main at 4a1b788 with the sRGB change from #11613 applied, which touches only colour creation. macOS 26.6.2.