Anchors for Tailwind CSS is a plugin that brings declarative support for the CSS Anchor Positioning API to Tailwind CSS. It provides utilities for defining anchors (anchor-name
) and positioning elements relative to them (position-anchor
, position-area
, anchor()
, anchor-size()
), as well as utilities for advanced features like conditional visibility (position-visibility
) and fallback positioning (position-try-order
, position-try-fallbacks
).
It also lays the groundwork for using View Transitions to animate any anchored elements, which would require separate JS (for now 👀).
-
Install the plugin from npm with your preferred package manager:
npm install -D @toolwind/anchors
-
Then include it in your Tailwind CSS or JS config file:
CSS (Tailwind CSS v4+)
/* style.css */ @import "@toolwind/anchors";
JS (Tailwind CSS v3 compatible)
// tailwind.config.js import anchors from "@toolwind/anchors";
Use the anchor/{name}
utility to define an anchor point. The CSS anchor-name
property requires a dashed ident type (e.g. --my-anchor
). For convenience, Anchors for Tailwind CSS automatically converts simpler ident types (e.g. my-anchor
) names into dashed idents under the hood.
There are several ways to define an anchor:
-
Use a non-dashed ident (e.g.
my-anchor
)<div class="anchor/my-anchor"></div>
This utlity generates the below CSS, prefixed with
--tw-anchor_
since CSSanchor-name
property requires a dashed ident type (e.g.--my-anchor
), as mentioned previously:.anchor\/my-anchor { anchor-name: --tw-anchor_my-anchor; }
-
Use a dashed ident (e.g.
--my-anchor
)If you explicitly specify a dashed ident as an anchor name, this utility will preserve that dashed ident so you can re-use it elsewhere more easily.
<div class="anchor/--my-anchor"></div>
This will generate the following CSS:
.anchor\/--my-anchor { anchor-name: --my-anchor; }
-
Use an arbitrary value (e.g.
[var(--x)]
or[--my-anchor]
)🚧 Note that names passed via an arbitrary value (square bracket syntax) must be or resolve to a dashed ident.
-
Include a variable reference inside an arbitrary value (e.g.
[var(--x)]
)If you want to pass a name via a CSS variable, you can do so using an arbitrary value (square bracket syntax), like this:
<div class="[--x:--my-anchor]"> <div class="anchor/[var(--x)]"></div> </div>
This will generate the following CSS:
.anchor\/\[var\(--x\)\] { anchor-name: var(--x); } .\[--x\:--my-anchor\] { --x: var(--my-anchor); }
For an even simpler syntax, take a look at the variable shorthand syntax under point 4 below.
-
Include dashed ident inside arbitrary value (e.g.
[--my-anchor]
)You can directly pass a dashed ident using the square bracket syntax:
<div class="anchor/[--my-anchor]"></div>
This will generate the following CSS:
.anchor\/\[--my-anchor\] { anchor-name: --my-anchor; }
However, while this approach works, it is equivalent to using the dashed ident syntax shown in example 2 (
anchor/--my-anchor
), which is simpler.[!WARNING] Note that Tailwind v3.x treats this syntax as differently, and will process
anchor/[--my-anchor]
asanchor-name: var(--my-anchor)
instead ofanchor-name: --my-anchor
, as it uses this as the syntax for variable shorthand syntax. See point 4 below for more information.
-
-
Pass a variable using variable shorthand syntax
-
Tailwind CSS v4.x
In Tailwind CSS v4.x and above, you can use this shorthand below instead of passing a custom property reference to an arbitrary value (square bracket syntax).
These two utilities are equivalent, and will both produce
anchor-name: var(--x)
:<div class="anchor/[var(--x)]"></div> <div class="anchor/(--x)"></div>
[!IMPORTANT] This is not the same as
anchor/--my-anchor
oranchor/[--my-anchor]
, as they pass the dashed ident itself directly, where the variable shorthand syntax wraps its value invar()
. -
Tailwind CSS v3.x (≥ 3.3 and above)
Using variable shorthand syntax in Tailwind v3.x (≥ 3.3 and above), you can use square brackets to reference CSS variables, similarly to the v4 example above, only using square brackets instead of parentheses.
These two utilities are equivalent, and will both produce
anchor-name: var(--x)
:<div class="anchor/[var(--x)]"></div> <div class="anchor/[--x]"></div>
[!IMPORTANT] This behavior differs from Tailwind CSS v4 and newer, where
anchor/[--x]
would pass the dashed ident directly. In Tailwind CSS v3, if you want to pass the dashed ident directly without wrapping it invar()
, use the dashed ident syntax shown in example 2 above.
-
Once an anchor has been defined, you can anchor other elements to it.
-
Anchoring: Attach an element to an anchor
Use
anchored/{name}
to attach an element to an anchor:<div class="anchored/my-anchor"></div>
{ position-anchor: --tw-anchor_my-anchor; :where(&) { position: absolute; view-transition-name: --tw-anchor-view-transition-313d192p322r2w3336; } }
-
Positioning: Position an element relative its linked anchor
Use
anchored-{side}
to specify the position area of the anchored element. For example,anchored-top-center
will position the element at the top center of its anchor, touching the anchored element:<div class="anchored-top-center"></div>
{ position-area: top center; }
-
Shorthand: Anchor and position an element relative to an anchor
Use
anchored-{side}/{name}
to combine anchoring and positioning in a single utility:<div class="anchored-top-center/my-anchor"></div>
{ position-anchor: --tw-anchor_my-anchor; position-area: top center; :where(&) { position: absolute; view-transition-name: --tw-anchor-view-transition-313d192p322r2w3336; } }
Important
A quick note on the use of :where()
here:
Using :where()
in a CSS selector resets the specificity of the styles declared inside that selector's block to zero, meaning they hold the lowest priority in selector matching. This makes it extremely easy for you to override these values.
Because this plugin sets both position
and view-transition-name
with zero specificity, you can override both of these styles with ease without having to worry about using !
(!important
) on your overriding styles. making them easy to overwrite with other values, if you choose.
As a rule of thumb, anchored elements must use absolute or fixed positioning. This plugin defaults to absolute
positioning, but you can add fixed
to use fixed positioning instead for any anchored element.
Because of the way the view-transition-name
value is encoded, it really shouldn't conflict with any of your other styles, but if you wish to opt of that being applied as well, you can simple add [view-transition-name:none]
to your classes for the anchored element (alongside the anchored
utility classes).
-
Sets
anchor-name
-
Sets:
position-anchor
-
Sets
position-area
. Examples:anchored-top-center
→top center
anchored-bottom-span-left
→bottom span-left
anchored-right
→right
-
Generates explicit directional positioning using
anchor()
:<div class="top-anchor-bottom"></div>
Results in:
top: anchor(bottom);
With offset support:
<div class="top-anchor-bottom-4"></div>
top: calc(anchor(bottom) + 1rem);
-
Sets size utilities using
anchor-size()
:-
Omitting the anchor size (i.e. default size/dimension)
w-anchor
→width: anchor-size(width)
If a size is omitted, the size value is set to the same size on the linked anchor element for the property being set.
For example, (
w-anchor
) would 8000 setwidth: anchor-size()
, which is equivalent towidth: anchor-size(width)
, setting the width of the anchored element equal to the width of its linked anchor.For further reading:
anchor-size#anchor-size
(MDN) -
Declaring the anchor-size (width/height/etc.) to use as a length
w-anchor-height
→width: anchor-size(height)
This example sets the anchored element's width to the height of its linked anchor element. This is useful when you want to create elements with dimensions based on different aspects of their anchor elements.
-
Setting/omitting the anchor name
w-anchor
→width: anchor-size(width)
w-anchor/--name
→width: anchor-size(--name width)
w-anchor/name
→width: anchor-size(--tw-anchor_name width)
Specifying an anchor name on an anchor size utility is entirely optional when setting sizes relevant to an anchored element's linked anchor element.
However, it only defines which anchor the element's property values should be set relative to.
For further reading:
anchor-size#anchor-size
(MDN)
-
-
Controls when the anchored element is visible.
anchored-visible-always
: Always visible (default behavior if property isn't set).anchored-visible-anchor
: Visible only when the anchor is at least partially visible.anchored-visible-no-overflow
: Visible only when the anchored element does not overflow the viewport.- Arbitrary values:
anchored-visible-[custom-value]
-
Sets the order for trying fallback positions.
try-order-normal
: Tries fallbacks in the order they are defined (default).try-order-w
: Prioritizes fallbacks that maximize width within the viewport.try-order-h
: Prioritizes fallbacks that maximize height within the viewport.- Arbitrary values:
try-order-[custom-value]
-
Defines the fallback positions to attempt.
try-none
: No fallbacks.try-flip-all
: Flips horizontally, vertically, and diagonally (flip-block, flip-inline, flip-block flip-inline
).try-flip-x
: Flips horizontally (flip-inline
).try-flip-y
: Flips vertically (flip-block
).try-flip-s
: Flips based on writing mode start direction (flip-start
).- Position area values:
try-top
,try-bottom-left
,try-left-span-top
, etc. (maps to the correspondingposition-area
value, e.g.,try-top
→top
). - Arbitrary values:
try-[custom-value]
Every anchored/{name}
class includes a view-transition-name
, making your anchored elements animatable with document.startViewTransition()
:
document.startViewTransition(() => {
el.classList.remove('anchored-top-left')
el.classList.add('anchored-bottom-right')
})
This animates position shifts smoothly using the browser-native View Transitions API.
- Declarative anchor positioning with Tailwind utility syntax
- Full support for native anchor-related CSS properties and functions
- Easy offset control via
calc(anchor(...) + theme spacing)
(under the hood) - Built-in support for View Transitions
- Fully JIT-compatible, no runtime required
- MDN: Guide: Using CSS anchor positioning | anchor-size() | anchor() | anchor-name | position-anchor | position-area | position-visibility | position-try-order | position-try-fallbacks
- CSS Tricks: CSS Anchor Positioning Guide
- Specification: CSS Anchor Positioning
- The Anchor Tool 👈 probably the best way to get a real fast introduction to the CSS Anchor Positioning API, how it works, and how helpful it can be ✨
- @Una! I've never met anyone more fired up about CSS Anchor Positioning than Una Kravets, so definitely check out some of the things she's posted about it. I'm not 100% certain, but I think she may have actually created the The Anchor Tool mentioned above.
Check out more by @branmcconnell:
- tailwindcss-signals: React to parent or ancestor state
- tailwindcss-members: Style based on child/descendant state
- tailwindcss-mixins: Reusable, aliased groups of utilities
- tailwindcss-selector-patterns: Dynamic selector composition
- tailwindcss-directional-shadows: Shadows with directional awareness
- tailwindcss-default-shades: Simpler default color utility names
- tailwindcss-js: Effortless script injection
- tailwindcss-multi: Group utility declarations under variants
- tailwind-lerp-colors: Flexible color interpolation and palette tooling