Exported on 11/25/2025 at 01:52:39 GMT+1 from Cursor (2.1.25)
User
Radix UI supports a functionality called trim. Here's a link describing it. How can I recreate exactly the same behavior without using Radix themes?
https://www.radix-ui.com/themes/docs/components/text
Cursor
Reviewing the current typography styles to understand the setup.
Recreating Radix UI's trim using negative margins to trim leading space. Here's a CSS implementation you can add to your typography styles:
/* Leading trim utilities - Recreates Radix UI trim functionality */
/* Uses negative margins to trim leading space, similar to half-leading control */
:root {
/* Default trim values - adjust these based on your font stack */
--leading-trim-start: 0.42em;
--leading-trim-end: 0.36em;
/* Heading-specific trim values */
--heading-leading-trim-start: 0.42em;
--heading-leading-trim-end: 0.36em;
}
/* Trim start - removes leading space at the top */
@utility trim-start {
margin-top: calc(-1 * var(--leading-trim-start));
}
/* Trim end - removes leading space at the bottom */
@utility trim-end {
margin-bottom: calc(-1 * var(--leading-trim-end));
}
/* Trim both - removes leading space at top and bottom */
@utility trim-both {
margin-top: calc(-1 * var(--leading-trim-start));
margin-bottom: calc(-1 * var(--leading-trim-end));
}
/* Heading-specific trim utilities */
@utility trim-heading-start {
margin-top: calc(-1 * var(--heading-leading-trim-start));
}
@utility trim-heading-end {
margin-bottom: calc(-1 * var(--heading-leading-trim-end));
}
@utility trim-heading-both {
margin-top: calc(-1 * var(--heading-leading-trim-start));
margin-bottom: calc(-1 * var(--heading-leading-trim-end));
}Usage examples:
// Trim start only
<p className="trim-start">Text with trimmed top leading</p>
// Trim end only
<p className="trim-end">Text with trimmed bottom leading</p>
// Trim both
<p className="trim-both">Text with trimmed top and bottom leading</p>
// For headings
<h1 className="trim-heading-both">Heading with trimmed leading</h1>How it works:
- Uses negative margins to offset the leading space
trim-startremoves top leadingtrim-endremoves bottom leadingtrim-bothremoves both- CSS variables let you adjust values per font
Adjusting for your fonts:
If you use custom fonts (e.g., Freight Neo), you may need to tune the CSS variables. Test visually and adjust --leading-trim-start and --leading-trim-end until spacing matches your design.
Should I add this to your typography.css file, or do you want to adjust the values first?
/* Leading trim utilities - Recreates Radix UI trim functionality */
/* Uses negative margins to trim leading space, similar to half-leading control */
:root {
/* Default trim values - adjust these based on your font stack */
--leading-trim-start: 0.42em;
--leading-trim-end: 0.36em;
/* Heading-specific trim values */
--heading-leading-trim-start: 0.42em;
--heading-leading-trim-end: 0.36em;
}
/* Trim start - removes leading space at the top */
@utility trim-start {
margin-top: calc(-1 * var(--leading-trim-start));
}
/* Trim end - removes leading space at the bottom */
@utility trim-end {
margin-bottom: calc(-1 * var(--leading-trim-end));
}
/* Trim both - removes leading space at top and bottom */
@utility trim-both {
margin-top: calc(-1 * var(--leading-trim-start));
margin-bottom: calc(-1 * var(--leading-trim-end));
}
/* Heading-specific trim utilities */
@utility trim-heading-start {
margin-top: calc(-1 * var(--heading-leading-trim-start));
}
@utility trim-heading-end {
margin-bottom: calc(-1 * var(--heading-leading-trim-end));
}
@utility trim-heading-both {
margin-top: calc(-1 * var(--heading-leading-trim-start));
margin-bottom: calc(-1 * var(--heading-leading-trim-end));
}// Trim start only
<p className="trim-start">Text with trimmed top leading</p>
// Trim end only
<p className="trim-end">Text with trimmed bottom leading</p>
// Trim both
<p className="trim-both">Text with trimmed top and bottom leading</p>
// For headings
<h1 className="trim-heading-both">Heading with trimmed leading</h1>
User
How should I go about adjusting custom values if I'm using multiple fonts and multiple weights?
Cursor
Checking which fonts and weights are used in the project to tailor the trim values.
Here’s a practical approach for handling trim values across multiple fonts and weights:
Use CSS custom properties scoped by font family and optionally by weight. This keeps values organized and easy to adjust.
/* Leading trim utilities - Recreates Radix UI trim functionality */
:root {
/* Default trim values - fallback for system fonts */
--leading-trim-start: 0.42em;
--leading-trim-end: 0.36em;
/* Museum font (your local font) */
--leading-trim-start-museum: 0.42em;
--leading-trim-end-museum: 0.36em;
/* Museum font by weight */
--leading-trim-start-museum-400: 0.42em;
--leading-trim-end-museum-400: 0.36em;
--leading-trim-start-museum-500: 0.42em;
--leading-trim-end-museum-500: 0.36em;
--leading-trim-start-museum-700: 0.45em; /* Bold often needs more trim */
--leading-trim-end-museum-700: 0.38em;
/* Freight Neo (Adobe Fonts) */
--leading-trim-start-freight-neo: 0.40em;
--leading-trim-end-freight-neo: 0.35em;
/* Freight Text Pro */
--leading-trim-start-freight-text: 0.43em;
--leading-trim-end-freight-text: 0.37em;
/* Freight Sans Pro */
--leading-trim-start-freight-sans: 0.41em;
--leading-trim-end-freight-sans: 0.36em;
/* Monospace - usually needs less trim */
--leading-trim-start-monospace: 0.35em;
--leading-trim-end-monospace: 0.30em;
}
/* Scoped by font-family using CSS cascade */
.font-museum {
--leading-trim-start: var(--leading-trim-start-museum);
--leading-trim-end: var(--leading-trim-end-museum);
}
.font-freight-neo {
--leading-trim-start: var(--leading-trim-start-freight-neo);
--leading-trim-end: var(--leading-trim-end-freight-neo);
}
.font-freight-text {
--leading-trim-start: var(--leading-trim-start-freight-text);
--leading-trim-end: var(--leading-trim-end-freight-text);
}
.font-freight-sans {
--leading-trim-start: var(--leading-trim-start-freight-sans);
--leading-trim-end: var(--leading-trim-end-freight-sans);
}
.font-monospace {
--leading-trim-start: var(--leading-trim-start-monospace);
--leading-trim-end: var(--leading-trim-end-monospace);
}
/* Weight-specific overrides (more specific = higher priority) */
.font-museum.font-weight-400 {
--leading-trim-start: var(--leading-trim-start-museum-400);
--leading-trim-end: var(--leading-trim-end-museum-400);
}
.font-museum.font-weight-500 {
--leading-trim-start: var(--leading-trim-start-museum-500);
--leading-trim-end: var(--leading-trim-end-museum-500);
}
.font-museum.font-weight-700 {
--leading-trim-start: var(--leading-trim-start-museum-700);
--leading-trim-end: var(--leading-trim-end-museum-700);
}
/* Base trim utilities - use CSS variables that cascade */
@utility trim-start {
margin-top: calc(-1 * var(--leading-trim-start));
}
@utility trim-end {
margin-bottom: calc(-1 * var(--leading-trim-end));
}
@utility trim-both {
margin-top: calc(-1 * var(--leading-trim-start));
margin-bottom: calc(-1 * var(--leading-trim-end));
}- Create a test page with bordered containers:
<div className="border-2 border-dashed p-4">
<p className="font-museum font-normal trim-both">
Test text with trim
</p>
</div>- Compare with and without trim — the padding should look equal on all sides when trimmed.
- Inspect the text element and check Computed →
line-height. - Measure the visual gap above/below the text.
- Calculate:
trim-value = (line-height - font-size) / 2(rough starting point). - Adjust in 0.01em increments until spacing looks balanced.
Create a test component to compare all combinations:
// Test component (temporary, for measurement)
const fonts = ['museum', 'freight-neo', 'freight-text', 'freight-sans'];
const weights = [400, 500, 700];
fonts.map(font =>
weights.map(weight => (
<div key={`${font}-${weight}`} className="border p-4">
<p className={`font-${font} font-weight-${weight} trim-both`}>
{font} {weight}
</p>
</div>
))
)If you prefer explicit control per element:
/* Data attribute scoping */
[data-font="museum"][data-weight="400"] {
--leading-trim-start: 0.42em;
--leading-trim-end: 0.36em;
}
[data-font="museum"][data-weight="700"] {
--leading-trim-start: 0.45em;
--leading-trim-end: 0.38em;
}Usage:
<p data-font="museum" data-weight="700" className="trim-both">
Bold Museum text
</p>- Start with Radix defaults (0.42em/0.36em) for all fonts.
- Test visually with bordered containers.
- Adjust per font family first (largest differences).
- Then adjust per weight if needed (bold often needs more).
- Document your final values in comments.
- Bold weights often need 0.02–0.05em more trim.
- Serif fonts may differ from sans-serif.
- Italic variants may need slight adjustments.
- Test at different font sizes — trim values scale with
em. - Use browser DevTools to toggle trim classes and compare.
Should I create a test page component to help you measure these values, or do you want to start with the CSS structure above and adjust as needed?
/* Leading trim utilities - Recreates Radix UI trim functionality */
:root {
/* Default trim values - fallback for system fonts */
--leading-trim-start: 0.42em;
--leading-trim-end: 0.36em;
/* Museum font (your local font) */
--leading-trim-start-museum: 0.42em;
--leading-trim-end-museum: 0.36em;
/* Museum font by weight */
--leading-trim-start-museum-400: 0.42em;
--leading-trim-end-museum-400: 0.36em;
--leading-trim-start-museum-500: 0.42em;
--leading-trim-end-museum-500: 0.36em;
--leading-trim-start-museum-700: 0.45em; /* Bold often needs more trim */
--leading-trim-end-museum-700: 0.38em;
/* Freight Neo (Adobe Fonts) */
--leading-trim-start-freight-neo: 0.40em;
--leading-trim-end-freight-neo: 0.35em;
/* Freight Text Pro */
--leading-trim-start-freight-text: 0.43em;
--leading-trim-end-freight-text: 0.37em;
/* Freight Sans Pro */
--leading-trim-start-freight-sans: 0.41em;
--leading-trim-end-freight-sans: 0.36em;
/* Monospace - usually needs less trim */
--leading-trim-start-monospace: 0.35em;
--leading-trim-end-monospace: 0.30em;
}
/* Scoped by font-family using CSS cascade */
.font-museum {
--leading-trim-start: var(--leading-trim-start-museum);
--leading-trim-end: var(--leading-trim-end-museum);
}
.font-freight-neo {
--leading-trim-start: var(--leading-trim-start-freight-neo);
--leading-trim-end: var(--leading-trim-end-freight-neo);
}
.font-freight-text {
--leading-trim-start: var(--leading-trim-start-freight-text);
--leading-trim-end: var(--leading-trim-end-freight-text);
}
.font-freight-sans {
--leading-trim-start: var(--leading-trim-start-freight-sans);
--leading-trim-end: var(--leading-trim-end-freight-sans);
}
.font-monospace {
--leading-trim-start: var(--leading-trim-start-monospace);
--leading-trim-end: var(--leading-trim-end-monospace);
}
/* Weight-specific overrides (more specific = higher priority) */
.font-museum.font-weight-400 {
--leading-trim-start: var(--leading-trim-start-museum-400);
--leading-trim-end: var(--leading-trim-end-museum-400);
}
.font-museum.font-weight-500 {
--leading-trim-start: var(--leading-trim-start-museum-500);
--leading-trim-end: var(--leading-trim-end-museum-500);
}
.font-museum.font-weight-700 {
--leading-trim-start: var(--leading-trim-start-museum-700);
--leading-trim-end: var(--leading-trim-end-museum-700);
}
/* Base trim utilities - use CSS variables that cascade */
@utility trim-start {
margin-top: calc(-1 * var(--leading-trim-start));
}
@utility trim-end {
margin-bottom: calc(-1 * var(--leading-trim-end));
}
@utility trim-both {
margin-top: calc(-1 * var(--leading-trim-start));
margin-bottom: calc(-1 * var(--leading-trim-end));
}<div className="border-2 border-dashed p-4">
<p className="font-museum font-normal trim-both">
Test text with trim
</p>
</div>
// Test component (temporary, for measurement)
const fonts = ['museum', 'freight-neo', 'freight-text', 'freight-sans'];
const weights = [400, 500, 700];
fonts.map(font =>
weights.map(weight => (
<div key={`${font}-${weight}`} className="border p-4">
<p className={`font-${font} font-weight-${weight} trim-both`}>
{font} {weight}
</p>
</div>
))
)
/* Data attribute scoping */
[data-font="museum"][data-weight="400"] {
--leading-trim-start: 0.42em;
--leading-trim-end: 0.36em;
}
[data-font="museum"][data-weight="700"] {
--leading-trim-start: 0.45em;
--leading-trim-end: 0.38em;
}<p data-font="museum" data-weight="700" className="trim-both">
Bold Museum text
</p>
User
Is there some canonical CSS property that does exactly the same thing without me having to use any hacks?
Cursor
Searching for native CSS properties that handle leading trim without hacks.
There are two CSS properties that handle this natively:
Designed to trim leading space in text boxes, matching Radix UI's trim behavior:
.text-element {
text-box-trim: trim-both;
text-box-edge: cap alphabetic;
}Values:
text-box-trim:trim-start|trim-end|trim-both|nonetext-box-edge: Defines the reference edges (e.g.,cap alphabeticfor cap height top, alphabetic baseline bottom)
Example:
@utility trim-start {
text-box-trim: trim-start;
text-box-edge: cap alphabetic;
}
@utility trim-end {
text-box-trim: trim-end;
text-box-edge: cap alphabetic;
}
@utility trim-both {
text-box-trim: trim-both;
text-box-edge: cap alphabetic;
}Trims child margins at container edges:
.container {
margin-trim: block; /* trims top/bottom margins */
}Both are experimental. Use progressive enhancement with a fallback:
/* Leading trim utilities with progressive enhancement */
/* Modern browsers: use native text-box-trim */
@utility trim-start {
text-box-trim: trim-start;
text-box-edge: cap alphabetic;
/* Fallback for browsers without support */
@supports not (text-box-trim: trim-start) {
margin-top: calc(-1 * var(--leading-trim-start, 0.42em));
}
}
@utility trim-end {
text-box-trim: trim-end;
text-box-edge: cap alphabetic;
@supports not (text-box-trim: trim-end) {
margin-bottom: calc(-1 * var(--leading-trim-end, 0.36em));
}
}
@utility trim-both {
text-box-trim: trim-both;
text-box-edge: cap alphabetic;
@supports not (text-box-trim: trim-both) {
margin-top: calc(-1 * var(--leading-trim-start, 0.42em));
margin-bottom: calc(-1 * var(--leading-trim-end, 0.36em));
}
}text-box-trim: Limited support (Safari 17.4+, Chrome/Edge behind flags)margin-trim: Limited support (Safari 16.4+)
Use text-box-trim with the negative margin fallback. This gives you:
- Native behavior where supported
- Fallback for older browsers
- Future-proof code
The @supports query ensures the fallback only applies when needed, so modern browsers use the native property.
Should I update your typography.css with this progressive enhancement approach?
.text-element {
text-box-trim: trim-both;
text-box-edge: cap alphabetic;
}@utility trim-start {
text-box-trim: trim-start;
text-box-edge: cap alphabetic;
}
@utility trim-end {
text-box-trim: trim-end;
text-box-edge: cap alphabetic;
}
@utility trim-both {
text-box-trim: trim-both;
text-box-edge: cap alphabetic;
}.container {
margin-trim: block; /* trims top/bottom margins */
}/* Leading trim utilities with progressive enhancement */
/* Modern browsers: use native text-box-trim */
@utility trim-start {
text-box-trim: trim-start;
text-box-edge: cap alphabetic;
/* Fallback for browsers without support */
@supports not (text-box-trim: trim-start) {
margin-top: calc(-1 * var(--leading-trim-start, 0.42em));
}
}
@utility trim-end {
text-box-trim: trim-end;
text-box-edge: cap alphabetic;
@supports not (text-box-trim: trim-end) {
margin-bottom: calc(-1 * var(--leading-trim-end, 0.36em));
}
}
@utility trim-both {
text-box-trim: trim-both;
text-box-edge: cap alphabetic;
@supports not (text-box-trim: trim-both) {
margin-top: calc(-1 * var(--leading-trim-start, 0.42em));
margin-bottom: calc(-1 * var(--leading-trim-end, 0.36em));
}
}