Annotation
annotationAdds a handwritten-style highlight, arrow, or note around inline content in eight positions.
Usage
Basic usage
Encloses a piece of inline content, note is the handwritten marginalia. side says **where the label is** (same as Tooltip/Popover), and the arrow automatically points back to the target from the label. The label is absolutely positioned and does not occupy the layout position, so leave space around the container.
<p>
Task ID is written as <Annotation note="Stable ID" side="ne">CLI-042</Annotation>,
You won't lose contact even if you change the title.
</p>Dissecting a line of code
The most typical use of annotation: break down a line of things and talk about them piece by piece. When hanging multiple labels in the same line, use side to stagger the directions, and use offset to fine-tune them if necessary. The last three strips are close to each other. Use --hl-ann-spread to narrow the outward expansion of the highlighter, so that the background color will not be connected into a whole piece and cannot be separated from the boundary.
- [ ] CLI-042Stable ID Add export command #cliTags !highPriority @blocked_by:CLI-041Custom fields<code>
- [ ] <Annotation note="Stable ID" side="n" tone="primary">CLI-042</Annotation>{" "}
Add export command{" "}
<Annotation note="tag" side="n" tone="success" className="[--hl-ann-spread:0.1em]">#cli</Annotation>{" "}
<Annotation note="Priority" side="s" tone="danger" className="[--hl-ann-spread:0.1em]">!high</Annotation>{" "}
<Annotation note="Custom field" side="se" tone="warning" className="[--hl-ann-spread:0.1em]">
@blocked_by:CLI-041
</Annotation>
</code>Eight directions
side is the location of the label. The four positive orientation anchors are centered on corresponding sides, and the four diagonal orientation anchors are aligned toward the outside at the target corners—the label will only grow away from the target as it lengthens.
{["n", "ne", "e", "se", "s", "sw", "w", "nw"].map((side) => (
<Annotation key={side} note={side} side={side}>Target</Annotation>
))}Tone color
tone only dyes and annotates itself (the background color of the highlighter is derived from it), and the annotated text remains in its original color. rainbow is a cycle of hues, purely for decoration; it will stop at the starting color when the animation preference is reduced.
<Annotation note="Neutral" tone="neutral">Default</Annotation>
<Annotation note="Main Color" tone="primary">Accent</Annotation>
<Annotation note="Correct answer" tone="success">Passed</Annotation>
<Annotation note="Attention" tone="warning">Warning</Annotation>
<Annotation note="pit" tone="danger">Danger</Annotation>
<Annotation note="Rainbow" tone="rainbow">Decoration</Annotation>Just circle without note
If note is not passed, only the highlighter background color will be left, and no arrows or labels will be drawn - used to simply circle a piece of content. On the other hand, mark={false} retains the annotation and removes the background color.
<p>
What really matters is <Annotation tone="warning">this sentence</Annotation>,
The rest is <Annotation note="Can be skipped" side="s" mark={false}>Background explanation</Annotation>.
</p>Label ReactNode
note is a real DOM node rather than a content pseudo-element of CSS, so it can be placed in any ReactNode - embedded code, links, emphasis, and can be read by screen readers.
docs/specs<Annotation
note={<>See <code>docs/specs</code></>}
side="e"
tone="primary"
>
spec file
</Annotation>Handwritten fonts and alignment
The Chinese fonts (Handwritten/Pianpian/Xingkai) in the handwriting font stack are system fonts, which are only available if they are installed; if they are not installed, they will fall back to the main text fonts, and the tilt angle and color matching are still there. To be more restrained in formal documents, you can use handwritten={false} with rotate={0}.
<Annotation note="Handwriting · Default slant" side="n">Default</Annotation>
<Annotation note="Text · Straighten" side="n" handwritten={false} rotate={0}>Restraint</Annotation>When to use
Use Annotation to explain a specific inline fragment in documentation, presentations, or component diagrams, such as a piece of code, configuration, or URL.
It complements Callout: Callout interrupts the document with a block, while Annotation adds an out-of-flow note. Use Tour for interactive product guidance or Tooltip for hover-triggered explanations.
Import
import { Annotation } from "@hulianui/ui/annotation"Props
| Name | Type | Default | Description |
|---|---|---|---|
| note | ReactNode | — | Handwritten label content. Omit it for a highlight without an arrow or label. |
| side | "n"|"ne"|"e"|"se"|"s"|"sw"|"w"|"nw" | ne | Label position; the arrow points back to the target. |
| tone | "neutral"|"primary"|"success"|"warning"|"danger"|"rainbow" | neutral | Annotation color; the annotated content keeps its own color. |
| mark | boolean | true | Shows the highlighter background controlled by --hl-ann-spread. |
| rotate | number | -4 | Label rotation in degrees; use 0 to align it. |
| labelWidth | number | 150 | Maximum label width before wrapping, in pixels. |
| gap | number | 5 | Space between the target and arrow, in pixels. |
| labelGap | number | 6 | Space between the arrow and label, in pixels. |
| offset | { x?: number; y?: number } | — | Fine adjustment; positive values move away on the side axis and right or down on the other axis. |
| handwritten | boolean | true | Applies the handwritten font stack described below. |
| as | ElementType | span | Host element; use mark when semantic highlighting is appropriate. |
| className | string | — | Class on the annotated host. |
| labelClassName | string | — | Class on the label for typography adjustments. |
CSS variables
| Variable | Default | Description |
|---|---|---|
--hl-annotation-font | Handwritten font stack | Global stack from @hulianui/tokens semantic.css; override it site-wide as needed. |
--hl-ann-spread | 0.3em | Horizontal highlight spread. Override one item with className="[--hl-ann-spread:0.1em]". |
Pitfalls
Ancestors with `overflow: hidden` clip the label. The arrow and label are absolutely positioned outside the target box. Add padding to clipped containers such as ScrollArea, cards, and table cells, choose another side, and reserve surrounding space.
Adjacent highlights can merge. The default 0.3em horizontal spread mimics an overdrawn marker. Reduce --hl-ann-spread to 0.1em or 0px; keep the unit because unitless zero can invalidate the calculated box-shadow length.
Handwritten fonts depend on the system. The Latin and CJK faces in --hl-annotation-font are not bundled. If no face matches, the label falls back to the body font. Load your own font with @font-face and override the variable when handwritten rendering must be guaranteed.
Do not put required information only in `note`. It is real DOM content and can be read by assistive technology, but remains visually secondary and follows the target in reading order. Repeat instructions, errors, and state in the primary content.
`tone` does not recolor the target text. It only sets the annotation arrow and label through --hl-ann-color; apply a text class through className when the target itself should change.
Related
Playground
<Annotation note="Stable ID" side="ne" tone="neutral">CLI-042</Annotation>