Skip to main content
Nathan_Peters
New Member
April 18, 2024

Add Variable support for Letter Case

letter-case-var

It would be really helpful to be able to use a variable to set a Type Style’s Letter Case (under the Type Settings meatball menu).

It could be a String Variable, and the options would be “As entered”, “Uppercase”, “Lowercase”, “Title case”, and “Small caps”.

I personally use modes to switch between different brands, and some brand styles require uppercase while others don’t allow it. This suggestion may be a small feature in the grand scheme, but I wonder if others would also find it useful.

51 replies

tjango
New Member
September 23, 2026

Measured: which text properties accept setBoundVariable, and which don't

I ran into this building a multi-brand design system where the brand itself is a variable mode, so instead of guessing I measured the whole surface of the Plugin API on a plain TextNode.

setBoundVariable(field, variable) — accepted: fontSize, fontFamily, fontStyle, fontWeight, letterSpacing, lineHeight, paragraphSpacing, paragraphIndent, characters.

Refused: textCase → in setBoundVariable: Unknown field: 'textCase', and textDecoration → in setBoundVariable: Unknown field: 'textDecoration'.

Note that node.textCase = "UPPER" works fine, so the property itself is there — only the binding is missing. Every one of its neighbours in the same Typography section of the panel binds.

Why this matters beyond styling: when the brand is a variable mode, everything else about a component follows that mode — colour, radius, spacing, font family, font weight. Letter case is the single typographic decision that cannot, so a component set in a two-brand file can only ever show one brand's casing. The obvious workaround — binding characters to a per-mode string — does work, but only for a placeholder: the moment a designer types their own label into an instance, the binding is gone and the casing stops following the brand.

For context, CSS has had text-transform since forever, and Penpot ships text-case and text-decoration as first-class token types. So this reads like a gap rather than a conceptual problem.

Happy to share the probe script if it's useful.