neat-annotations does not reserve the space its labels occupy
Hand-drawn CSS annotations for inline content
At a glance
- What is it?
- Hand-drawn CSS arrows and handwritten labels for inline content, delivered as one stylesheet with no JavaScript and no build step. Ten custom properties and eight direction classes cover the geometry, and the README is explicit that annotations sit outside their target without pushing anything around.
- Who is it for?
- neat-annotations fits documentation, changelogs and inline explainers where a sentence needs a pointer and a scribbled label, and it costs one link tag and two class names to adopt. It is not a tooltip library, and the distinction matters: nothing appears on hover, nothing is focusable, and the label is always visible, which makes it better for explanation than for interface chrome.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 18 days ago.
- What is it written in?
- Mainly HTML, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 4, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One stylesheet, and the whole integration is a link tag
The delivery is a single file with no JavaScript and no build step, which is the project's main claim and the reason it can drop into a static page. You either point at the copy on jsDelivr:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/syabro/neat-annotations/neat-annotations.css">or download `neat-annotations.css` and serve it yourself. Nothing else is required. Annotating a piece of text means wrapping it in a span with the base class and a label attribute, for example `class="ann ann-n ann-amber" data-note="no refresh needed"` around the words `in real time`. The base class draws the underline treatment, the direction class decides where the arrow points, the color class picks a palette, and `data-note` carries the text of the label. There is no configuration object and no JavaScript entry point to register.
Annotations do not reserve space, so they will overlap
The layout note is the single most important line in the README and it is easy to skim past. Annotations are positioned outside their target and do not reserve space, so you have to leave enough margin around annotated lines for the arrow and the label. There is no collision detection, no stacking and no reflow. That is a deliberate trade: absolute positioning is what makes the effect possible without JavaScript, and the cost is that the annotated line needs breathing room in advance. On a dense paragraph in a narrow column the label will overlap the next line, and nothing in the stylesheet tries to prevent it. If your layout is fluid, test at the width where the text is longest rather than at your development viewport, since the label width is what overflows, not the span.
Eight directions, one base class, and the arrow points at the text
A direction class names where the arrow points rather than where the label sits, which is the detail to internalise. `ann-n` places the label below the target and points the arrow north toward it. The full set is `ann-n`, `ann-ne`, `ann-e`, `ann-se`, `ann-s`, `ann-sw`, `ann-w` and `ann-nw`, so the arrow always terminates on the thing you annotated. The markup for the simplest case is a span with two classes, `ann ann-n`, and a `data-note` of `points north`. Annotations can also be nested, which is how you point at one target from several sides at once, and that is the pattern to reach for rather than trying to fit a long sentence into one label.
Six color classes, and rainbow respects reduced motion
The default is a theme-aware warm gray, and six classes override it: `ann-amber`, `ann-blue`, `ann-green`, `ann-red`, `ann-purple` and `ann-rainbow`. A color class changes the arrow, the label and the target highlight together, which is the behaviour to plan around: you cannot tint the arrow without tinting the underline on the text. That keeps things coherent at the cost of fine control. `ann-rainbow` animates through hues and respects `prefers-reduced-motion`, so it is the one class with motion behaviour attached and it is the one that has already been made safe for users who asked for less. Anything outside the six is done through the custom property rather than a class.
Custom colors go through --ann-color, and light-dark() is built in
Any CSS color can be set directly with `--ann-color` in a style attribute, which covers the long tail the six classes do not. The interesting part is the theme-aware form, where the value is a `light-dark()` call so a custom color follows the light and dark themes without a media query:
<span class="ann ann-n" data-note="..." style="--ann-color: light-dark(#111111, #f5f5f7)">adaptive</span>That single function is what the rest of the stylesheet uses for its defaults too, which is why the built-in palette reads as theme-aware warm gray rather than a fixed hex. The practical consequence for you is that a custom color written as a plain hex will look wrong in one of the two themes, and the fix is the function rather than a second declaration. Where the color is only decorative, a plain value is fine.
Drop data-note for a marker, and ann-no-mark to keep your own fill
Two reductions turn the effect into something smaller. Omit `data-note` and the direction class and the span becomes a text marker with no arrow and no label, so `class="ann ann-amber"` around the word `important` gives you a colored highlight with no decoration around it. The second is for the case where the target already carries its own background: adding `ann-no-mark` removes the highlight so the arrow points at something that looks like itself again. The example wraps an existing badge span, so a nested element keeps its own fill while the annotation attaches to it. Both reductions are worth knowing because the common failure in a design system is a highlight fighting with a component background, and this is the escape hatch.
Ten custom properties cover geometry, spacing and tilt
Fine tuning is a table of variables set directly on an annotated element, and the defaults are unusually opinionated. `--ann-color` sets arrow and label color, `--ann-mark` the target highlight, `--ann-font` the label font, defaulting to Shantell Sans with a cursive fallback. Spacing is four variables: `--ann-target-gap` at 5px, `--ann-label-gap` at 6px, and `--ann-lower-label-gap` at minus 4px, which is the correction for labels sitting below the target. Layout is four more, `--ann-arrow-x`, `--ann-arrow-y`, `--ann-text-x` and `--ann-text-y` defaulting to zero and 5px. The last is `--ann-rotate` at minus 4 degrees, the label tilt, and `--ann-label-max-width` at 150px is where long notes start wrapping. Removing that tilt is the first thing to try if the handwriting reads as sloppy rather than deliberate.
The accessibility rule is a prohibition, not a caveat
The README states that annotations are visual enhancements and that you must not use `data-note` as the only source of instructions, status, validation or other essential information. The remedies it offers are both about real HTML: repeat important content in visible HTML, or connect a real description to the target with `aria-describedby`. That is the correct instinct, since a label positioned outside the flow and reached through a pseudo-element is not reliably announced by a screen reader, and a validation message delivered that way is a message some users never receive. Two related details round out the picture. The font is optional, loading Shantell Sans only matches the demo and otherwise falls back to a cursive face, which is a rendering difference rather than a content one. And the repository ships a `CNAME` and `index.html` alongside the stylesheet, so the demo is served from its own domain rather than from GitHub Pages.
Editorial conclusion
neat-annotations fits documentation, changelogs and inline explainers where a sentence needs a pointer and a scribbled label, and it costs one link tag and two class names to adopt. It is not a tooltip library, and the distinction matters: nothing appears on hover, nothing is focusable, and the label is always visible, which makes it better for explanation than for interface chrome. Two constraints to design around. Annotations are positioned outside their target and do not reserve space, so a paragraph that gains a label will overlap whatever sits beside it unless you leave margin on the annotated line, and that is a layout decision you have to make in your own stylesheet. And the accessibility note is a rule, not a suggestion: do not carry instructions or status in `data-note`, because the label text is decorative and a screen reader may never reach it. Use `aria-describedby` when the text matters.
Frequently asked questions
How do I add neat-annotations to a page?
Add one link tag for the stylesheet, from jsDelivr or a local copy of neat-annotations.css, then wrap the text you want annotated in a span with the base `ann` class, a direction class and a `data-note` holding the label text. There is no JavaScript and no build step.
Does neat-annotations need JavaScript?
No. The project is described as pure CSS with no JavaScript and no build step, delivered as one self-contained stylesheet. All positioning, colors and spacing come from CSS classes and custom properties.
How do I change the color of a neat-annotations arrow?
Use one of the six built-in classes, ann-amber, ann-blue, ann-green, ann-red, ann-purple or ann-rainbow, which change the arrow, label and target highlight together. For any other color set the `--ann-color` property, optionally with `light-dark()` so it adapts to light and dark themes.
Will neat-annotations overlap my other content?
It can. Annotations are positioned outside their target and do not reserve space, so the README tells you to leave enough margin around annotated lines for the arrow and label. Long labels wrap at 150px by default, set with `--ann-label-max-width`.
Is neat-annotations accessible for screen reader users?
The annotations are visual enhancements. The README says not to use data-note as the only source of instructions, status or validation, and instead to repeat important content in visible HTML or link a real description with aria-describedby. The rainbow class respects prefers-reduced-motion.
Can I use neat-annotations without the hand-drawn font?
Yes. Shantell Sans is optional and is only needed to match the demo. Without it, labels fall back to a cursive font, and you can change the family entirely with the `--ann-font` property, whose default is 'Shantell Sans', cursive.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/syabro-neat-annotations)