Pure TailwindMIT licensed

Tailwind IDE Function Signature Tooltip with Typed Docs Popover

The typed-signature popover a code editor shows on hover: badge, namespace path, multi-line signature, prose, a parameter table and a footer shortcut. The port's interesting cost is whitespace-pre — the CSS version fights inheritance with two resets, and Tailwind makes both of them visible on the elements that need them.

Live Demo
Plain CSSTailwind v4
Try it

Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time

Untitled UI React · Affiliate link

Get Untitled UI Pro

The code

<section class="ttp-03 w-full min-h-svh flex items-start justify-center bg-ttp03-bg font-ttp03-mono px-7 pt-[300px] pb-12">
  <div class="w-full max-w-[560px] bg-ttp03-panel border border-ttp03-edge rounded-lg shadow-[0_18px_50px_-16px_rgba(0,0,0,0.7)]">
    <div class="flex items-center gap-1 h-8 px-3.5 bg-ttp03-bg border-b border-ttp03-edge rounded-t-lg">
      <span class="w-[9px] h-[9px] rounded-full bg-[#ff5f57]"></span>
      <span class="w-[9px] h-[9px] rounded-full bg-[#febc2e]"></span>
      <span class="w-[9px] h-[9px] rounded-full bg-[#28c840]"></span>
      <span class="ml-4.5 inline-flex items-center gap-[7px] px-3 py-[5px] rounded-t-md bg-ttp03-panel text-[11px] text-ttp03-ink before:content-[''] before:w-1 before:h-1 before:rounded-full before:bg-ttp03-blue">orchestrator.ts</span>
    </div>

    <div class="flex py-4.5 text-[13px] leading-[22px] text-ttp03-ink">
      <div class="w-11 pr-3 text-right select-none border-r border-ttp03-rule text-ttp03-gutter text-[13px]">
        <div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div><div>7</div><div>8</div>
      </div>
      <div class="flex-1 min-w-0 px-4">
        <div><span class="italic text-ttp03-cmt">// pipeline assembled at boot</span></div>
        <div><span class="text-ttp03-kw">import</span> { <span class="text-ttp03-fn">createScheduler</span> } <span class="text-ttp03-kw">from</span> <span class="text-ttp03-str">"./scheduler"</span>;</div>
        <div>&nbsp;</div>
        <div><span class="text-ttp03-kw">const</span> <span class="text-ttp03-var">queue</span> = <button type="button" aria-describedby="ttp03-tip" class="group relative inline cursor-help border-0 bg-transparent p-0 px-0.5 rounded-[2px] font-ttp03-mono text-[13px] [border-bottom:1px_dashed_rgba(88,166,255,0.55)] transition-colors duration-200 hover:bg-ttp03-blue/10 hover:[border-bottom-color:#58a6ff] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ttp03-blue after:content-['ⓘ'] after:inline-block after:align-middle after:ml-[3px] after:text-[9px] after:text-ttp03-blue/60 hover:after:text-ttp03-blue"><span class="text-ttp03-fn">createScheduler</span><span id="ttp03-tip" role="tooltip" class="pointer-events-none absolute bottom-[calc(100%+14px)] left-[-20px] z-10 block w-[380px] max-w-[calc(100vw-56px)] text-left whitespace-normal leading-normal translate-y-2 opacity-0 rounded-md border border-ttp03-edge bg-linear-to-b from-ttp03-card1 to-ttp03-card2 shadow-[0_18px_50px_-8px_rgba(0,0,0,0.75),0_0_0_1px_rgba(88,166,255,0.06),inset_0_1px_0_rgba(255,255,255,0.04)] transition-[opacity,translate] duration-200 ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0 motion-reduce:transition-opacity after:content-[''] after:absolute after:top-full after:left-8 after:w-2.5 after:h-2.5 after:-translate-y-1/2 after:rotate-45 after:bg-ttp03-panel after:border-r after:border-b after:border-ttp03-edge">
          <span class="flex items-center gap-2.5 px-3.5 pt-2.5 pb-2.25 border-b border-ttp03-rule text-[11px]">
            <span class="rounded-[10px] bg-ttp03-blue/15 px-1.75 py-0.5 text-[10px] font-semibold tracking-[0.05em] text-ttp03-blue">FUNCTION</span>
            <span class="text-ttp03-dim">core<span class="mx-1 text-ttp03-gutter">›</span>scheduler<span class="mx-1 text-ttp03-gutter">›</span>createScheduler</span>
          </span>
          <span class="block whitespace-pre border-b border-ttp03-rule px-3.5 py-3 text-xs leading-[1.6]"><span class="text-ttp03-kw">function</span> <span class="text-ttp03-fn">createScheduler</span>&lt;<span class="text-ttp03-var">T</span>&gt;(
  <span class="text-ttp03-param">opts</span>: <span class="text-ttp03-var">SchedulerOptions</span>&lt;<span class="text-ttp03-var">T</span>&gt;
): <span class="text-ttp03-var">Queue</span>&lt;<span class="text-ttp03-var">T</span>&gt;</span>
          <span class="block border-b border-ttp03-rule px-3.5 py-3 font-ttp03-sans text-xs leading-[1.65] text-ttp03-ink">Creates a back-pressured task queue with concurrency control. Items are processed in <code class="rounded-[3px] bg-ttp03-chip px-1.25 py-px font-ttp03-mono text-[11px] text-ttp03-param">FIFO</code> order; failing jobs surface to the dead-letter sink.</span>
          <span class="block border-b border-ttp03-rule px-3.5 py-2.5">
            <span class="grid grid-cols-[90px_1fr] gap-2.5 py-0.75 text-[11.5px] leading-[1.5]"><span class="text-ttp03-param">concurrency</span><span class="font-ttp03-sans text-ttp03-dim">Max parallel jobs. Default <code class="rounded-[3px] bg-ttp03-chip px-1.25 py-px font-ttp03-mono text-[11px] text-ttp03-param">4</code>.</span></span>
            <span class="grid grid-cols-[90px_1fr] gap-2.5 py-0.75 text-[11.5px] leading-[1.5]"><span class="text-ttp03-param">retries</span><span class="font-ttp03-sans text-ttp03-dim">Per-task retry budget. Default <code class="rounded-[3px] bg-ttp03-chip px-1.25 py-px font-ttp03-mono text-[11px] text-ttp03-param">3</code>.</span></span>
            <span class="grid grid-cols-[90px_1fr] gap-2.5 py-0.75 text-[11.5px] leading-[1.5]"><span class="text-ttp03-param">onDrain</span><span class="font-ttp03-sans text-ttp03-dim">Fires once when the queue empties.</span></span>
          </span>
          <span class="flex items-center justify-between px-3.5 py-2.25 text-[10.5px] text-ttp03-dim">
            <span>scheduler.ts · L42</span>
            <span><kbd class="not-italic"><span class="mx-0.5 inline-block rounded-[4px] border border-ttp03-edge border-b-2 bg-ttp03-chipdark px-1.5 py-px text-[10px] text-ttp03-ink">⌘</span><span class="mx-0.5 inline-block rounded-[4px] border border-ttp03-edge border-b-2 bg-ttp03-chipdark px-1.5 py-px text-[10px] text-ttp03-ink">K</span></kbd> for docs</span>
          </span>
        </span></button>({</div>
        <div>&nbsp;&nbsp;<span class="text-ttp03-param">concurrency</span>: <span class="text-ttp03-num">8</span>,</div>
        <div>&nbsp;&nbsp;<span class="text-ttp03-param">retries</span>: <span class="text-ttp03-num">3</span>,</div>
        <div>});</div>
      </div>
    </div>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-ttp03-bg: #0d1117;
  --color-ttp03-bg: oklch(0.18 0.02 265);
  --color-ttp03-panel: #161b22;
  --color-ttp03-panel: oklch(0.22 0.02 265);
  --color-ttp03-card1: #1c2128;
  --color-ttp03-card1: oklch(0.25 0.02 265);
  --color-ttp03-card2: #161b22;
  --color-ttp03-card2: oklch(0.22 0.02 265);
  --color-ttp03-edge: #30363d;
  --color-ttp03-edge: oklch(0.35 0.01 265);
  --color-ttp03-rule: #21262d;
  --color-ttp03-chip: #3a4049;
  --color-ttp03-chip: oklch(0.38 0.01 265);
  --color-ttp03-chipdark: #21262d;
  --color-ttp03-ink: #c9d1d9;
  --color-ttp03-ink: oklch(0.85 0.01 265);
  --color-ttp03-dim: #9aa4b0;
  --color-ttp03-dim: oklch(0.72 0.014 265);
  --color-ttp03-gutter: #6e7681;
  --color-ttp03-gutter: oklch(0.56 0.01 265);
  --color-ttp03-blue: #58a6ff;
  --color-ttp03-blue: oklch(0.71 0.14 255);
  --color-ttp03-kw: #ff7b72;
  --color-ttp03-fn: #d2a8ff;
  --color-ttp03-str: #a5d6ff;
  --color-ttp03-num: #79c0ff;
  --color-ttp03-var: #79c0ff;
  --color-ttp03-cmt: #9aa4b0;
  --color-ttp03-param: #ffa657;
  --font-ttp03-mono: 'JetBrains Mono', ui-monospace, monospace;
  --font-ttp03-sans: 'Inter', system-ui, sans-serif;
}

.ttp-03 {
  width: 100%;
  min-height: 100svh;
}

Setup — do this once per project

Skip this if your project already runs Tailwind v4.

1Load Tailwind
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

Compiles in the browser — perfect for a CodePen or a quick test, not for production.

2Add the stylesheetRequiredthe @theme block is what makes the custom utilities exist
@import "tailwindcss";

@theme {
  --color-ttp03-bg: #0d1117;
  --color-ttp03-bg: oklch(0.18 0.02 265);
  --color-ttp03-panel: #161b22;
  --color-ttp03-panel: oklch(0.22 0.02 265);
  --color-ttp03-card1: #1c2128;
  --color-ttp03-card1: oklch(0.25 0.02 265);
  --color-ttp03-card2: #161b22;
  --color-ttp03-card2: oklch(0.22 0.02 265);
  --color-ttp03-edge: #30363d;
  --color-ttp03-edge: oklch(0.35 0.01 265);
  --color-ttp03-rule: #21262d;
  --color-ttp03-chip: #3a4049;
  --color-ttp03-chip: oklch(0.38 0.01 265);
  --color-ttp03-chipdark: #21262d;
  --color-ttp03-ink: #c9d1d9;
  --color-ttp03-ink: oklch(0.85 0.01 265);
  --color-ttp03-dim: #9aa4b0;
  --color-ttp03-dim: oklch(0.72 0.014 265);
  --color-ttp03-gutter: #6e7681;
  --color-ttp03-gutter: oklch(0.56 0.01 265);
  --color-ttp03-blue: #58a6ff;
  --color-ttp03-blue: oklch(0.71 0.14 255);
  --color-ttp03-kw: #ff7b72;
  --color-ttp03-fn: #d2a8ff;
  --color-ttp03-str: #a5d6ff;
  --color-ttp03-num: #79c0ff;
  --color-ttp03-var: #79c0ff;
  --color-ttp03-cmt: #9aa4b0;
  --color-ttp03-param: #ffa657;
  --font-ttp03-mono: 'JetBrains Mono', ui-monospace, monospace;
  --font-ttp03-sans: 'Inter', system-ui, sans-serif;
}

.ttp-03 {
  width: 100%;
  min-height: 100svh;
}
3Fonts used by this demooptional — skip if you have your own type stack
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500;600&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • Seven syntax colours as @theme entries is the port's quiet win: text-ttp03-kw and friends mean a theme swap touches the stylesheet only, exactly like a real editor.
  • The two inheritance resets the CSS version buries in comments (white-space and line-height) are now whitespace-normal leading-normal on the card and whitespace-pre on the signature — visible on the elements they fix.
  • UI change from the CSS original: the hover symbol is a <button>, so the docs are keyboard-reachable; the gutter grey went #484f58 → #6e7681 and the comment/param-description grey #8b949e → #9aa4b0, both of which sat under 4.5:1 on #161b22; and the card is clamped with max-w-[calc(100vw-56px)].
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind IDE Function Signature Tooltip with Typed Docs Popover
Source: https://codefronts.com/snippets/tailwind-css-tooltips/tailwind-ide-function-signature-tooltip-typed-docs-popover/

The typed-signature popover a code editor shows on hover: badge, namespace path, multi-line signature, prose, a parameter table and a footer shortcut. The port's interesting cost is whitespace-pre &mdash; the CSS version fights inheritance with two resets, and Tailwind makes both of them visible on the elements that need them.
## HTML
```html
<section class="ttp-03 w-full min-h-svh flex items-start justify-center bg-ttp03-bg font-ttp03-mono px-7 pt-[300px] pb-12">
  <div class="w-full max-w-[560px] bg-ttp03-panel border border-ttp03-edge rounded-lg shadow-[0_18px_50px_-16px_rgba(0,0,0,0.7)]">
    <div class="flex items-center gap-1 h-8 px-3.5 bg-ttp03-bg border-b border-ttp03-edge rounded-t-lg">
      <span class="w-[9px] h-[9px] rounded-full bg-[#ff5f57]"></span>
      <span class="w-[9px] h-[9px] rounded-full bg-[#febc2e]"></span>
      <span class="w-[9px] h-[9px] rounded-full bg-[#28c840]"></span>
      <span class="ml-4.5 inline-flex items-center gap-[7px] px-3 py-[5px] rounded-t-md bg-ttp03-panel text-[11px] text-ttp03-ink before:content-[''] before:w-1 before:h-1 before:rounded-full before:bg-ttp03-blue">orchestrator.ts</span>
    </div>

    <div class="flex py-4.5 text-[13px] leading-[22px] text-ttp03-ink">
      <div class="w-11 pr-3 text-right select-none border-r border-ttp03-rule text-ttp03-gutter text-[13px]">
        <div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div><div>7</div><div>8</div>
      </div>
      <div class="flex-1 min-w-0 px-4">
        <div><span class="italic text-ttp03-cmt">// pipeline assembled at boot</span></div>
        <div><span class="text-ttp03-kw">import</span> { <span class="text-ttp03-fn">createScheduler</span> } <span class="text-ttp03-kw">from</span> <span class="text-ttp03-str">"./scheduler"</span>;</div>
        <div>&nbsp;</div>
        <div><span class="text-ttp03-kw">const</span> <span class="text-ttp03-var">queue</span> = <button type="button" aria-describedby="ttp03-tip" class="group relative inline cursor-help border-0 bg-transparent p-0 px-0.5 rounded-[2px] font-ttp03-mono text-[13px] [border-bottom:1px_dashed_rgba(88,166,255,0.55)] transition-colors duration-200 hover:bg-ttp03-blue/10 hover:[border-bottom-color:#58a6ff] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ttp03-blue after:content-['ⓘ'] after:inline-block after:align-middle after:ml-[3px] after:text-[9px] after:text-ttp03-blue/60 hover:after:text-ttp03-blue"><span class="text-ttp03-fn">createScheduler</span><span id="ttp03-tip" role="tooltip" class="pointer-events-none absolute bottom-[calc(100%+14px)] left-[-20px] z-10 block w-[380px] max-w-[calc(100vw-56px)] text-left whitespace-normal leading-normal translate-y-2 opacity-0 rounded-md border border-ttp03-edge bg-linear-to-b from-ttp03-card1 to-ttp03-card2 shadow-[0_18px_50px_-8px_rgba(0,0,0,0.75),0_0_0_1px_rgba(88,166,255,0.06),inset_0_1px_0_rgba(255,255,255,0.04)] transition-[opacity,translate] duration-200 ease-[cubic-bezier(0.22,1,0.36,1)] group-hover:opacity-100 group-hover:translate-y-0 group-focus-visible:opacity-100 group-focus-visible:translate-y-0 motion-reduce:transition-opacity after:content-[''] after:absolute after:top-full after:left-8 after:w-2.5 after:h-2.5 after:-translate-y-1/2 after:rotate-45 after:bg-ttp03-panel after:border-r after:border-b after:border-ttp03-edge">
          <span class="flex items-center gap-2.5 px-3.5 pt-2.5 pb-2.25 border-b border-ttp03-rule text-[11px]">
            <span class="rounded-[10px] bg-ttp03-blue/15 px-1.75 py-0.5 text-[10px] font-semibold tracking-[0.05em] text-ttp03-blue">FUNCTION</span>
            <span class="text-ttp03-dim">core<span class="mx-1 text-ttp03-gutter">›</span>scheduler<span class="mx-1 text-ttp03-gutter">›</span>createScheduler</span>
          </span>
          <span class="block whitespace-pre border-b border-ttp03-rule px-3.5 py-3 text-xs leading-[1.6]"><span class="text-ttp03-kw">function</span> <span class="text-ttp03-fn">createScheduler</span>&lt;<span class="text-ttp03-var">T</span>&gt;(
  <span class="text-ttp03-param">opts</span>: <span class="text-ttp03-var">SchedulerOptions</span>&lt;<span class="text-ttp03-var">T</span>&gt;
): <span class="text-ttp03-var">Queue</span>&lt;<span class="text-ttp03-var">T</span>&gt;</span>
          <span class="block border-b border-ttp03-rule px-3.5 py-3 font-ttp03-sans text-xs leading-[1.65] text-ttp03-ink">Creates a back-pressured task queue with concurrency control. Items are processed in <code class="rounded-[3px] bg-ttp03-chip px-1.25 py-px font-ttp03-mono text-[11px] text-ttp03-param">FIFO</code> order; failing jobs surface to the dead-letter sink.</span>
          <span class="block border-b border-ttp03-rule px-3.5 py-2.5">
            <span class="grid grid-cols-[90px_1fr] gap-2.5 py-0.75 text-[11.5px] leading-[1.5]"><span class="text-ttp03-param">concurrency</span><span class="font-ttp03-sans text-ttp03-dim">Max parallel jobs. Default <code class="rounded-[3px] bg-ttp03-chip px-1.25 py-px font-ttp03-mono text-[11px] text-ttp03-param">4</code>.</span></span>
            <span class="grid grid-cols-[90px_1fr] gap-2.5 py-0.75 text-[11.5px] leading-[1.5]"><span class="text-ttp03-param">retries</span><span class="font-ttp03-sans text-ttp03-dim">Per-task retry budget. Default <code class="rounded-[3px] bg-ttp03-chip px-1.25 py-px font-ttp03-mono text-[11px] text-ttp03-param">3</code>.</span></span>
            <span class="grid grid-cols-[90px_1fr] gap-2.5 py-0.75 text-[11.5px] leading-[1.5]"><span class="text-ttp03-param">onDrain</span><span class="font-ttp03-sans text-ttp03-dim">Fires once when the queue empties.</span></span>
          </span>
          <span class="flex items-center justify-between px-3.5 py-2.25 text-[10.5px] text-ttp03-dim">
            <span>scheduler.ts · L42</span>
            <span><kbd class="not-italic"><span class="mx-0.5 inline-block rounded-[4px] border border-ttp03-edge border-b-2 bg-ttp03-chipdark px-1.5 py-px text-[10px] text-ttp03-ink">⌘</span><span class="mx-0.5 inline-block rounded-[4px] border border-ttp03-edge border-b-2 bg-ttp03-chipdark px-1.5 py-px text-[10px] text-ttp03-ink">K</span></kbd> for docs</span>
          </span>
        </span></button>({</div>
        <div>&nbsp;&nbsp;<span class="text-ttp03-param">concurrency</span>: <span class="text-ttp03-num">8</span>,</div>
        <div>&nbsp;&nbsp;<span class="text-ttp03-param">retries</span>: <span class="text-ttp03-num">3</span>,</div>
        <div>});</div>
      </div>
    </div>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-ttp03-bg: #0d1117;
  --color-ttp03-bg: oklch(0.18 0.02 265);
  --color-ttp03-panel: #161b22;
  --color-ttp03-panel: oklch(0.22 0.02 265);
  --color-ttp03-card1: #1c2128;
  --color-ttp03-card1: oklch(0.25 0.02 265);
  --color-ttp03-card2: #161b22;
  --color-ttp03-card2: oklch(0.22 0.02 265);
  --color-ttp03-edge: #30363d;
  --color-ttp03-edge: oklch(0.35 0.01 265);
  --color-ttp03-rule: #21262d;
  --color-ttp03-chip: #3a4049;
  --color-ttp03-chip: oklch(0.38 0.01 265);
  --color-ttp03-chipdark: #21262d;
  --color-ttp03-ink: #c9d1d9;
  --color-ttp03-ink: oklch(0.85 0.01 265);
  --color-ttp03-dim: #9aa4b0;
  --color-ttp03-dim: oklch(0.72 0.014 265);
  --color-ttp03-gutter: #6e7681;
  --color-ttp03-gutter: oklch(0.56 0.01 265);
  --color-ttp03-blue: #58a6ff;
  --color-ttp03-blue: oklch(0.71 0.14 255);
  --color-ttp03-kw: #ff7b72;
  --color-ttp03-fn: #d2a8ff;
  --color-ttp03-str: #a5d6ff;
  --color-ttp03-num: #79c0ff;
  --color-ttp03-var: #79c0ff;
  --color-ttp03-cmt: #9aa4b0;
  --color-ttp03-param: #ffa657;
  --font-ttp03-mono: 'JetBrains Mono', ui-monospace, monospace;
  --font-ttp03-sans: 'Inter', system-ui, sans-serif;
}

.ttp-03 {
  width: 100%;
  min-height: 100svh;
}
```

How this works

The symbol became a button. The CSS original hovered a <span>, so a keyboard user could never read the docs at all. Here the token is a real <button type="button" aria-describedby> that keeps its dashed-underline affordance and its trailing ⓘ discovery dot, and the popover answers both group-hover: and group-focus-visible:.

Syntax colours become tokens, not classes. Seven @theme colours mint text-ttp03-kw, text-ttp03-fn, text-ttp03-str and the rest, so a theme swap is seven lines and the markup is untouched — which is exactly how a real editor theme works.

Pixel line-height, deliberately. leading-[22px] on both the gutter and the code column is load-bearing: an em line-height across two font sizes drifts the numbers out of step with their lines by about 2px per row.

Make it yours

  • Retheme: the seven --color-ttp03-* syntax entries are the whole palette — drop in any editor theme's hexes and nothing else changes.
  • Card width w-[380px] and offset left-[-20px]; widen to 440px for languages with longer generic signatures.
  • Footer shortcut keycaps reuse the pattern from demo 02 — swap the glyphs for a Windows chord if your audience is not on macOS.

Gotchas — read before shipping

  • The popover must not inherit the editor's leading-[22px]; leading-normal on the card is what keeps its prose from looking double-spaced.
  • pointer-events-none on the card means a user cannot move the mouse INTO it — fine for a read-only popover, wrong the moment it contains a link. SC 1.4.13 requires hoverable content when it does.
  • A 380px card anchored inside a 560px editor overflows on narrow screens; the port clamps it with max-w-[calc(100vw-56px)].

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

everything here is transitions, gradients and grid; the floor quoted is Tailwind v4's own generated sheet.

Techniques used in this demo

Utilitiesfirst-class utility or variant

Search CodeFronts

Loading…