Skip to content

Conversation

ricardonunez-io
Copy link
Contributor

@ricardonunez-io ricardonunez-io commented Sep 16, 2025

Add Twoslash support via transformer to Shiki codeblock parsing step hidden behind explicit trigger.

Closes ENG-4255

Test Plan

Disable explicit triggers by setting explicitTrigger: false in rehypeSyntaxHighlighting.ts.

yarn build

In mint, replace all instances of "@mintlify/mdx" versions in package.json files with file:/path/to/mdx/packages/mdx and run yarn

Add the following CSS to `client` (this will be modified, but it's just to verify everything works)
/* ===== Basic ===== */
:root {
  --twoslash-border-color: #8888;
  --twoslash-underline-color: currentColor;
  --twoslash-highlighted-border: #c37d0d50;
  --twoslash-highlighted-bg: #c37d0d20;
  --twoslash-popup-bg: #f8f8f8;
  --twoslash-popup-color: inherit;
  --twoslash-popup-shadow: rgba(0, 0, 0, 0.08) 0px 1px 4px;
  --twoslash-docs-color: #888;
  --twoslash-docs-font: sans-serif;
  --twoslash-code-font: inherit;
  --twoslash-code-font-size: 1em;
  --twoslash-matched-color: inherit;
  --twoslash-unmatched-color: #888;
  --twoslash-cursor-color: #8888;
  --twoslash-error-color: #d45656;
  --twoslash-error-bg: #d4565620;
  --twoslash-warn-color: #c37d0d;
  --twoslash-warn-bg: #c37d0d20;
  --twoslash-tag-color: #3772cf;
  --twoslash-tag-bg: #3772cf20;
  --twoslash-tag-warn-color: var(--twoslash-warn-color);
  --twoslash-tag-warn-bg: var(--twoslash-warn-bg);
  --twoslash-tag-annotate-color: #1ba673;
  --twoslash-tag-annotate-bg: #1ba67320;
}

/* Respect people's wishes to not have animations */
@media (prefers-reduced-motion: reduce) {
  .twoslash * {
    transition: none !important;
  }
}

/* ===== Hover Info ===== */
.twoslash:hover .twoslash-hover {
  border-color: var(--twoslash-underline-color);
}

.twoslash .twoslash-hover {
  border-bottom: 1px dotted transparent;
  transition-timing-function: ease;
  transition: border-color 0.3s;
  position: relative;
}

.twoslash .twoslash-popup-container {
  position: absolute;
  opacity: 0;
  display: inline-flex;
  flex-direction: column;
  transform: translateY(1.1em);
  background: var(--twoslash-popup-bg);
  color: var(--twoslash-popup-color);
  border: 1px solid var(--twoslash-border-color);
  transition: opacity 0.3s;
  border-radius: 4px;
  pointer-events: none;
  z-index: 10;
  user-select: none;
  text-align: left;
  box-shadow: var(--twoslash-popup-shadow);
}

/* .twoslash .twoslash-query-presisted .twoslash-popup-container { */
/* z-index: 9; */
/* transform: translateY(1.5em); */
/* } */

.twoslash .twoslash-hover:hover .twoslash-popup-container,
.twoslash .twoslash-error-hover:hover .twoslash-popup-container,
/* .twoslash .twoslash-query-presisted .twoslash-popup-container, */
.twoslash .twoslash-query-line .twoslash-popup-container {
  opacity: 1;
  pointer-events: auto;
}

.twoslash .twoslash-popup-container:hover {
  user-select: auto;
}

.twoslash .twoslash-popup-arrow {
  position: absolute;
  top: -4px;
  left: 1em;
  border-top: 1px solid var(--twoslash-border-color);
  border-right: 1px solid var(--twoslash-border-color);
  background: var(--twoslash-popup-bg);
  transform: rotate(-45deg);
  width: 6px;
  height: 6px;
  pointer-events: none;
}

.twoslash .twoslash-popup-code,
.twoslash .twoslash-popup-error,
.twoslash .twoslash-popup-docs {
  padding: 6px 8px !important;
}

.twoslash .twoslash-popup-code {
  font-family: var(--twoslash-code-font);
  font-size: var(--twoslash-code-font-size);
}

.twoslash .twoslash-popup-docs {
  color: var(--twoslash-docs-color);
  font-family: var(--twoslash-docs-font);
  font-size: 0.8em;
  border-top: 1px solid var(--twoslash-border-color);
}

.twoslash .twoslash-popup-error {
  color: var(--twoslash-error-color);
  background-color: var(--twoslash-error-bg);
  font-family: var(--twoslash-docs-font);
  font-size: 0.8em;
}

.twoslash .twoslash-popup-docs-tags {
  display: flex;
  flex-direction: column;
  font-family: var(--twoslash-docs-font);
}

.twoslash .twoslash-popup-docs-tags,
.twoslash .twoslash-popup-docs-tag-name {
  margin-right: 0.5em;
}

.twoslash .twoslash-popup-docs-tag-name {
  font-family: var(--twoslash-code-font);
}

/* ===== Query Line ===== */
.twoslash .twoslash-query-line .twoslash-popup-container {
  position: relative;
  margin-bottom: 1.4em;
  transform: translateY(0.6em);
}

/* ===== Error Line ===== */
.twoslash .twoslash-error-line {
  position: relative;
  background-color: var(--twoslash-error-bg);
  border-left: 3px solid var(--twoslash-error-color);
  color: var(--twoslash-error-color);
  padding: 6px 12px;
  margin: 0.2em 0;
  min-width: 100%;
  width: max-content;
}

.twoslash .twoslash-error-line.twoslash-error-level-warning {
  background-color: var(--twoslash-warn-bg);
  border-left: 3px solid var(--twoslash-warn-color);
  color: var(--twoslash-warn-color);
}

.twoslash .twoslash-error {
  background: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23c94824'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E")
    repeat-x bottom left;
  padding-bottom: 2px;
}

.twoslash .twoslash-error.twoslash-error-level-warning {
  background: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23c37d0d'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E")
    repeat-x bottom left;
  padding-bottom: 2px;
}

/* ===== Completeions ===== */
.twoslash .twoslash-completion-cursor {
  position: relative;
}

.twoslash .twoslash-completion-cursor .twoslash-completion-list {
  user-select: none;
  position: absolute;
  top: 0;
  left: 0;
  transform: translate(0, 1.2em);
  margin: 3px 0 0 -1px;
  display: inline-block;
  z-index: 8;
  box-shadow: var(--twoslash-popup-shadow);
  background: var(--twoslash-popup-bg);
  border: 1px solid var(--twoslash-border-color);
}

.twoslash-completion-list {
  width: 240px;
  font-size: 0.8rem;
  padding: 4px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.twoslash-completion-list:hover {
  user-select: auto;
}

.twoslash-completion-list::before {
  background-color: var(--twoslash-cursor-color);
  width: 2px;
  position: absolute;
  top: -1.6em;
  height: 1.4em;
  left: -1px;
  content: " ";
}

.twoslash-completion-list li {
  overflow: hidden;
  display: flex;
  align-items: center;
  gap: 0.25em;
  line-height: 1em;
}

.twoslash-completion-list li span.twoslash-completions-unmatched {
  color: var(--twoslash-unmatched-color);
}

.twoslash-completion-list .deprecated {
  text-decoration: line-through;
  opacity: 0.5;
}

.twoslash-completion-list li span.twoslash-completions-matched {
  color: var(--twoslash-matched-color);
}

/* Highlights */
.twoslash-highlighted {
  background-color: var(--twoslash-highlighted-bg);
  border: 1px solid var(--twoslash-highlighted-border);
  padding: 1px 2px;
  margin: -1px -3px;
  border-radius: 4px;
}

/* Icons */
.twoslash-completion-list .twoslash-completions-icon {
  color: var(--twoslash-unmatched-color);
  width: 1em;
  flex: none;
}

/* Custom Tags */
.twoslash .twoslash-tag-line {
  position: relative;
  background-color: var(--twoslash-tag-bg);
  border-left: 3px solid var(--twoslash-tag-color);
  color: var(--twoslash-tag-color);
  padding: 6px 10px;
  margin: 0.2em 0;
  display: flex;
  align-items: center;
  gap: 0.3em;
  min-width: 100%;
  width: max-content;
}

.twoslash .twoslash-tag-line .twoslash-tag-icon {
  width: 1.1em;
  color: inherit;
}

.twoslash .twoslash-tag-line.twoslash-tag-error-line {
  background-color: var(--twoslash-error-bg);
  border-left: 3px solid var(--twoslash-error-color);
  color: var(--twoslash-error-color);
}

.twoslash .twoslash-tag-line.twoslash-tag-warn-line {
  background-color: var(--twoslash-tag-warn-bg);
  border-left: 3px solid var(--twoslash-tag-warn-color);
  color: var(--twoslash-tag-warn-color);
}

.twoslash .twoslash-tag-line.twoslash-tag-annotate-line {
  background-color: var(--twoslash-tag-annotate-bg);
  border-left: 3px solid var(--twoslash-tag-annotate-color);
  color: var(--twoslash-tag-annotate-color);
}

Open http://acme.localhost:3000/api/hello and look at the code blocks.

Copy link

vercel bot commented Sep 16, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
mdx-app-router Ready Ready Preview Comment Sep 17, 2025 9:32pm
mdx-pages-router Ready Ready Preview Comment Sep 17, 2025 9:32pm

Copy link
Contributor

@lawreka lawreka left a comment

Choose a reason for hiding this comment

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

couldn't get it to work with mint and local package according to the test plan, but the new examples in app-router and pages-router here give me confidence this is set up correctly and that that was user error. :lgtm: Lets Get This Merged!!

@ricardonunez-io ricardonunez-io merged commit c8045a8 into main Sep 17, 2025
3 checks passed
@ricardonunez-io ricardonunez-io deleted the ricardo/twoslash branch September 17, 2025 21:59
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