Tooltip

A tooltip annotation where the tooltip content can be any MDX content.

content.mdx
<CodeWithTooltips>
```js !code
// !tooltip[/lorem/] description
function lorem(ipsum, dolor = 1) {
const sit = ipsum == null ? 0 : ipsum.sit
dolor = sit - amet(dolor)
// !tooltip[/consectetur/] inspect
return sit ? consectetur(ipsum) : []
}
```
## !!tooltips description
### Hello world
Lorem ipsum **dolor** sit amet `consectetur`.
Adipiscing elit _sed_ do eiusmod.
## !!tooltips inspect
```js
function consectetur(ipsum) {
const { a, b } = ipsum
return a + b
}
```
</CodeWithTooltips>
function (ipsum, dolor = 1) {
const sit = ipsum == null ? 0 : ipsum.sit
dolor = sit - amet(dolor)
return sit ? (ipsum) : []
}

Hover (or focus) the lorem and consectetur tokens to see the respective tooltips.

Implementation

After we highlight the code, we find annotations where the query matches a tooltip title. If we find a match, we include the tooltip content in the annotation data.

code.tsx
import { Block, CodeBlock, parseProps } from "codehike/blocks"
import { Pre, highlight } from "codehike/code"
import { z } from "zod"
const Schema = Block.extend({
code: CodeBlock,
tooltips: z.array(Block).optional(),
})
async function CodeWithTooltips(props: unknown) {
const { code, tooltips = [] } = parseProps(props, Schema)
const highlighted = await highlight(code, theme)
highlighted.annotations = highlighted.annotations.map((a) => {
const tooltip = tooltips.find((t) => t.title === a.query)
if (!tooltip) return a
return {
...a,
data: { ...a.data, children: tooltip.children },

We store the tooltip content in the annotation data

}
})
return <Pre code={highlighted} handlers={[tooltip]} />
}

Then we define an AnnotationHandler to render the tooltip inline using the shadcn tooltip components (npx shadcn@latest add tooltip):

code.tsx
import { AnnotationHandler } from "codehike/code"
import {
TooltipProvider,
Tooltip,
TooltipTrigger,
TooltipContent,
} from "@/components/ui/tooltip"
const tooltip: AnnotationHandler = {
name: "tooltip",
Inline: ({ children, annotation }) => {
const { query, data } = annotation
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger className="underline decoration-dashed">
{children}
</TooltipTrigger>
<TooltipContent align="start">
{data?.children || query}
</TooltipContent>
</Tooltip>
</TooltipProvider>
)
},
}

Make it better

You can use the same concept to embed the MDX not only in tooltips but other annotations like callouts.