Skip to content

feat: \underbracket and \overbracket#4147

Merged
grigoriy-reshetniak merged 15 commits intoKaTeX:mainfrom
grigoriy-reshetniak:add-underbraket-overbracket
Mar 24, 2026
Merged

feat: \underbracket and \overbracket#4147
grigoriy-reshetniak merged 15 commits intoKaTeX:mainfrom
grigoriy-reshetniak:add-underbraket-overbracket

Conversation

@grigoriy-reshetniak
Copy link
Copy Markdown
Collaborator

@grigoriy-reshetniak grigoriy-reshetniak commented Feb 24, 2026

What is the new behavior after this PR?
Adds support for \underbracket and \overbracket.

I wasn't able to update screenshots due to images incompatibility.

Closes #4103

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Feb 24, 2026

Greptile Summary

This PR adds support for \overbracket and \underbracket LaTeX commands by extending the existing horizontal brace infrastructure. The implementation follows the established pattern used for \overbrace and \underbrace:

  • Adds the new commands to the horizBrace function definition (reuses all existing rendering logic)
  • Defines Unicode code points (U+23B4 and U+23B5) for MathML output
  • Provides SVG path geometry for bracket rendering, following the pattern of leftlinesegment/rightlinesegment
  • Includes comprehensive test coverage mirroring the existing brace tests
  • Updates documentation to reflect the newly supported commands

The implementation is clean, minimal, and leverages existing code effectively. All changes are consistent with the codebase patterns.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The changes follow established patterns exactly, reusing proven infrastructure for horizontal braces. The implementation is minimal (only adds function names, Unicode mappings, and SVG paths), includes comprehensive tests, and updates documentation appropriately. No complex logic changes or potential edge cases introduced.
  • No files require special attention

Important Files Changed

Filename Overview
src/functions/horizBrace.js Added \overbracket and \underbracket to existing horizontal brace function definition, simple extension of existing functionality
src/stretchy.js Added Unicode code points and image data for bracket SVG rendering, follows existing pattern for similar stretchy elements
src/svgGeometry.js Added SVG path definitions for left/right bracket over/under variants, consistent with existing line segment patterns
test/katex-spec.js Added comprehensive test coverage mirroring existing horizontal brace tests, validates parsing, building, and CSS classes

Last reviewed commit: 0d94372

Copy link
Copy Markdown
Member

@edemaine edemaine left a comment

Choose a reason for hiding this comment

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

Nice, thanks for picking this up!

You can download the new screenshot outputs from the failing CI tasks; they're uploaded as artifacts.

I'd consider merging the underbrace and underbracket tests, but don't feel strongly.

More importantly, I'm not sure the line widths are correct (seems too thin).
Also not sure about the height... should it be shorter?

\underline{hello}
\underbracket{hello}_{world} 
\underbrace{hello}_{world} 

KaTeX
KaTeX

LaTeX (with \usepackage{mathtools})
image

Unless there's another package that defines \underbracket?

There's also an issue with spacing before and after, but \underbrace has that too.

@grigoriy-reshetniak
Copy link
Copy Markdown
Collaborator Author

Thanks for the feedback, I'll work on the dimensions.

@grigoriy-reshetniak
Copy link
Copy Markdown
Collaborator Author

grigoriy-reshetniak commented Feb 24, 2026

I've addressed review comments:

  • Thickness and height are closer to LaTeX now (compared with mathtools)
image
  • Also it seems to me that mathtools puts some kern around brackets regardless of the surroundings, I've tried to replicate this too.
  • There are fewer unit tests.

@edemaine edemaine changed the title feat: add \underbraket and \overbracket feat: \underbracket and \overbracket Feb 24, 2026
Copy link
Copy Markdown
Member

@edemaine edemaine left a comment

Choose a reason for hiding this comment

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

Nice changes!

@ronkok
Copy link
Copy Markdown
Collaborator

ronkok commented Feb 27, 2026

I am commenting just to say that this PR is cool. @grigoriy-reshetniak, you are the first contributor other than me to use SVGs to extend KaTeX. I'm happy that someone has been able to follow and extend the methods that I used.

@edemaine has been maintaining KaTeX by himself for a while now, and I'm glad that you have stepped up to give him some support.

@grigoriy-reshetniak grigoriy-reshetniak force-pushed the add-underbraket-overbracket branch from e3d0647 to 4613b81 Compare March 6, 2026 21:22
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 6, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.30%. Comparing base (314f856) to head (7459f41).
⚠️ Report is 107 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #4147      +/-   ##
==========================================
+ Coverage   93.15%   93.30%   +0.14%     
==========================================
  Files          91       91              
  Lines        6795     6810      +15     
  Branches     1582     1585       +3     
==========================================
+ Hits         6330     6354      +24     
- Misses        429      454      +25     
+ Partials       36        2      -34     
Files with missing lines Coverage Δ
src/functions/horizBrace.ts 100.00% <100.00%> (ø)
src/stretchy.ts 87.50% <ø> (ø)
src/svgGeometry.ts 65.90% <ø> (ø)

... and 14 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 4aa75c5...7459f41. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Member

@edemaine edemaine left a comment

Choose a reason for hiding this comment

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

Looks great! Can you add the screenshots from the Screenshotter actions' uploaded artifacts?

Actually, a big oversight that CI passes! I confirmed that --verify doesn't give an exit code when a screenshot is missing, only (presumably) when there's a mismatch. We should fix in another PR.

@grigoriy-reshetniak
Copy link
Copy Markdown
Collaborator Author

grigoriy-reshetniak commented Mar 7, 2026

Can you add the screenshots from the Screenshotter actions' uploaded artifacts?

Unfortunately, I'm not able to find them. I'm able to see artifacts from failed builds, like https://github.com/KaTeX/KaTeX/actions/runs/22549692911, but its not available for successful ones (I believe because no diff is introduced), like https://github.com/KaTeX/KaTeX/actions/runs/22796025639?pr=4147.

This is KaTeX output in dev server for

\text{test}\underline{hello}\text{test}\underbracket{hello}_{world}\text{test}\underbrace{hello}_{world}\text{test}
\\[1em]
\text{test}\overline{hello}\text{test}\overbracket{hello}^{world}\text{test}\overbrace{hello}^{world}\text{test}
image

This is LaTeX output for the

\begin{align*}
  \text{test}\underline{hello}\text{test}\underbracket{hello}_{world}\text{test}\underbrace{hello}_{world}\text{test} \\[1em]
  \text{test}\overline{hello}\text{test}\overbracket{hello}^{world}\text{test}\overbrace{hello}^{world}\text{test}
\end{align*}
image

It seems to me that it's pretty close now.

@edemaine
Copy link
Copy Markdown
Member

edemaine commented Mar 7, 2026

(I believe because no diff is introduced

Actually I think this was #4158! Hopefully it works now.

@edemaine
Copy link
Copy Markdown
Member

edemaine commented Mar 7, 2026

I ran texcmp (from dockers/texcmp) on the screenshotter example and the two example lines from your comment, and they indeed look good:

HorizontalBrackets PR4147CommentOver PR4147CommentUnder

If I were to nit pick, I'd say the green (KaTeX) under/overbracket is slightly thicker. Did you get the line thickness measurement from LaTeX somewhere, or did you eyeball it? If it's from LaTeX, I'm happy to keep it as is; maybe just a browser rendering thing.

The horizontal spacing looks perfect! And ignore the sub/superscripts looking so different; that's #3972.

@grigoriy-reshetniak
Copy link
Copy Markdown
Collaborator Author

I did it by eye. However, I've checked documentation for mathtools and in 3.3.2 Braces and brackets it says:

The default rule thickness is equal to that of \underbrace (app. 5/18 ex)

KaTeX \underbrace is has thickness of 120 (SVG path), but current implementation of \underbracket has thickness of 100.

Per my understanding of documentation \underbracket should be even thicker (or \underbrace thinner to match). At the same time I made it thinner before and it seems to be too thick anyway.

What do you think?

@edemaine
Copy link
Copy Markdown
Member

edemaine commented Mar 7, 2026

I think I must have red and green backwards. Indeed, the texcmp README says green is LaTeX. (I was confused because LaTeX is the red channel, but light is additive, so...)

So overbracket is indeed too thin, and I'd up it to 120 like the documentation says.
Indeed, I think the right answer is approximately 120, which according to stretchy.js corresponds to 0.120em. This code:

\documentclass{article}
\begin{document}
$
\newlength\LEN
\setlength\LEN{1em}
\showthe\LEN
\setlength\LEN{0.277777ex}
\showthe\LEN
$
\end{document}

measures 1em at 10.00002pt and 5/18 ex at 1.19595pt, so 5/18 ex = 0.119595 em. Very close to 0.120em.

I agree it looks thick, but compatibility is a clearer target. In the future, we could try to make the thickness configurable — if that's even possible...

@edemaine
Copy link
Copy Markdown
Member

edemaine commented Mar 7, 2026

Here are the texcmp's with 120:

HorizontalBrackets PR4147CommentOver PR4147CommentUnder

I think this is a bit better: there's now both red and green of roughly equal amount. So the thickness seems right, just vertical offset is slightly off.

@ronkok
Copy link
Copy Markdown
Collaborator

ronkok commented Mar 7, 2026

I agree that \underbracket thickness should be 0.12 em, per mathtools docs and KaTeX fontMetrics definition of x-height.

To define \underbrace geometry, I converted a KaTeX font into an SVG font, copied a brace glyph, rotated it 90°, and used that path.

If you really want to make the thickness configurable, there is a go-by in current KaTeX settings. delimiter.js reads minRuleThickness from the KaTeX settings and passes a value to svgGeometry, which modifies the thickness of a sqrt vinculum. It's a lot of trouble for something used very infrequently. I recommend sticking with 0.12 em.

@grigoriy-reshetniak
Copy link
Copy Markdown
Collaborator Author

Next thing I need to do -- update docker images for screenshotter. I'm not able to run it on arm architecture so I have to take image from artifacts.

@edemaine
Copy link
Copy Markdown
Member

edemaine commented Mar 9, 2026

Here are the texcmp's with 120:

HorizontalBrackets

I reran texcmp and the offsets seem slightly worse:

HorizontalBrackets

The top red text seems slightly higher, and the bottom red text seems slightly lower, than before, but should be the other way around.

@grigoriy-reshetniak
Copy link
Copy Markdown
Collaborator Author

Here's fresh diff from texcmp:

image

Copy link
Copy Markdown
Member

@edemaine edemaine left a comment

Choose a reason for hiding this comment

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

Looks good! Just need to resolve a docs conflict.

@grigoriy-reshetniak grigoriy-reshetniak force-pushed the add-underbraket-overbracket branch from 6b0a862 to 1273009 Compare March 24, 2026 19:36
@grigoriy-reshetniak grigoriy-reshetniak force-pushed the add-underbraket-overbracket branch from 1273009 to 5b5ee4f Compare March 24, 2026 19:40
@grigoriy-reshetniak grigoriy-reshetniak merged commit 5be9abb into KaTeX:main Mar 24, 2026
9 checks passed
@grigoriy-reshetniak grigoriy-reshetniak deleted the add-underbraket-overbracket branch March 24, 2026 19:53
@edemaine
Copy link
Copy Markdown
Member

🎉 This PR is included in version 0.16.42 🎉

The release is available on:

Your semantic-release bot 📦🚀

alexander-turner pushed a commit to alexander-turner/KaTeX that referenced this pull request Mar 25, 2026
## [0.16.42](KaTeX/KaTeX@v0.16.41...v0.16.42) (2026-03-24)

### Features

* \underbracket and \overbracket ([KaTeX#4147](KaTeX#4147)) ([5be9abb](KaTeX@5be9abb))
dadezzz pushed a commit to dadezzz/ice-notes that referenced this pull request Mar 31, 2026
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [katex](https://katex.org) ([source](https://github.com/KaTeX/KaTeX)) | [`0.16.40` → `0.16.44`](https://renovatebot.com/diffs/npm/katex/0.16.40/0.16.44) | ![age](https://developer.mend.io/api/mc/badges/age/npm/katex/0.16.44?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/katex/0.16.40/0.16.44?slim=true) |

---

### Release Notes

<details>
<summary>KaTeX/KaTeX (katex)</summary>

### [`v0.16.44`](https://github.com/KaTeX/KaTeX/blob/HEAD/CHANGELOG.md#01644-2026-03-27)

[Compare Source](KaTeX/KaTeX@v0.16.43...v0.16.44)

##### Bug Fixes

- remove extra \jot space at bottom of align/gather/etc. ([#&#8203;4184](KaTeX/KaTeX#4184)) ([3870ee9](KaTeX/KaTeX@3870ee9))

### [`v0.16.43`](https://github.com/KaTeX/KaTeX/blob/HEAD/CHANGELOG.md#01643-2026-03-26)

[Compare Source](KaTeX/KaTeX@v0.16.42...v0.16.43)

##### Bug Fixes

- use makeEm() consistently to truncate long CSS decimals ([#&#8203;4181](KaTeX/KaTeX#4181)) ([0967dcc](KaTeX/KaTeX@0967dcc))

### [`v0.16.42`](https://github.com/KaTeX/KaTeX/blob/HEAD/CHANGELOG.md#01642-2026-03-24)

[Compare Source](KaTeX/KaTeX@v0.16.41...v0.16.42)

##### Features

- \underbracket and \overbracket ([#&#8203;4147](KaTeX/KaTeX#4147)) ([5be9abb](KaTeX/KaTeX@5be9abb))

### [`v0.16.41`](https://github.com/KaTeX/KaTeX/blob/HEAD/CHANGELOG.md#01641-2026-03-24)

[Compare Source](KaTeX/KaTeX@v0.16.40...v0.16.41)

##### Bug Fixes

- \sout in text mode ([#&#8203;4173](KaTeX/KaTeX#4173)) ([e748578](KaTeX/KaTeX@e748578))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My44Ni4wIiwidXBkYXRlZEluVmVyIjoiNDMuOTkuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: Renovate Bot <renovate@zarantonello.dev>
Co-committed-by: Renovate Bot <renovate@zarantonello.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for \underbracket and \overbracket

3 participants