{"id":34656699,"url":"https://github.com/johannesmutter/anchorpop","last_synced_at":"2025-12-24T18:09:33.425Z","repository":{"id":325085775,"uuid":"1095830284","full_name":"johannesmutter/anchorpop","owner":"johannesmutter","description":"Create self-positioning popovers with native CSS—no JavaScript required. Made for Svelte 5. Build tooltips, dropdowns and any floating UI components.","archived":false,"fork":false,"pushed_at":"2025-11-19T12:40:48.000Z","size":394,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-19T14:23:12.799Z","etag":null,"topics":["anchor-positioning","container-queries","css","dialog","dropdown","fallback","flip","floating-ui","popover","select-menu","svelte","tooltip"],"latest_commit_sha":null,"homepage":"https://anchorpop.fly.dev","language":"Svelte","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/johannesmutter.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"johannesmutter"}},"created_at":"2025-11-13T15:17:16.000Z","updated_at":"2025-11-19T12:52:14.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/johannesmutter/anchorpop","commit_stats":null,"previous_names":["johannesmutter/anchorpop"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/johannesmutter/anchorpop","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johannesmutter%2Fanchorpop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johannesmutter%2Fanchorpop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johannesmutter%2Fanchorpop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johannesmutter%2Fanchorpop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/johannesmutter","download_url":"https://codeload.github.com/johannesmutter/anchorpop/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johannesmutter%2Fanchorpop/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28005981,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-24T02:00:07.193Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anchor-positioning","container-queries","css","dialog","dropdown","fallback","flip","floating-ui","popover","select-menu","svelte","tooltip"],"created_at":"2025-12-24T18:05:47.655Z","updated_at":"2025-12-24T18:09:33.419Z","avatar_url":"https://github.com/johannesmutter.png","language":"Svelte","funding_links":["https://github.com/sponsors/johannesmutter"],"categories":[],"sub_categories":[],"readme":"# AnchorPop\n\n**CSS Anchor Positioning made simple for Svelte 5**\n\n🎯 **[Live Demo](https://anchorpop.fly.dev)** | 📦 **[npm](https://www.npmjs.com/package/anchorpop)** | 🐙 **[GitHub](https://github.com/johannesmutter/anchorpop)**\n\nAnchorPop is a lightweight library that brings the power of native CSS Anchor Positioning to Svelte applications. Create popovers, tooltips, dropdowns, and context menus that intelligently position themselves and automatically adjust when space is constrained.\n\n## Features\n\n- **Pure CSS Positioning** – Uses the native CSS Anchor Positioning API\n- **Automatic Fallbacks** – Intelligently flips when constrained by viewport\n- **Visual Arrows** – Optional connecting arrows that follow the popover\n- **Multiple Placements** – Outside, inside, overlay, and border positioning modes\n- **Zero Dependencies** – Just Svelte 5\n\n## Browser Support\n\nThis library requires browser support for CSS Anchor Positioning. Currently supported in:\n- Chrome/Edge (Arrows require 143+)\n- Safari (Arrows not yet supported due to lack of feature support for anchored container queries)\n\n## Installation\n\n```bash\nnpm install anchorpop\n```\n\n## Quick Start\n\n```svelte\n\u003cscript\u003e\n  import { AnchorPop, AnchorArrow, AnchorPopConfig } from 'anchorpop';\n\n  const config = new AnchorPopConfig({\n    id: 'my-popover',\n    placement: 'outside',\n    position_area: 'y-end',\n    align_self: 'start',\n    justify_self: 'anchor-center',\n    offset: 16\n  });\n\u003c/script\u003e\n\n\u003cbutton \n  popovertarget={config.id}\n  style=\"anchor-name: {config.from_anchor}\"\n\u003e\n  Click me\n\u003c/button\u003e\n\n\u003cAnchorPop {...config}\u003e\n  Your content here\n\u003c/AnchorPop\u003e\n\n\u003cAnchorArrow {...config} /\u003e\n```\n\n## Core Concepts\n\n### Placements\n\nAnchorPop supports four semantic placement modes:\n\n- **`outside`** – Never overlaps the anchor element. Perfect for tooltips, dropdowns, and context menus.\n- **`inside`** – Positioned within anchor bounds. Useful for overlay controls within containers.\n- **`overlay`** – Covers the anchor and extends beyond. Perfect for select-style menus.\n- **`border`** – Centered on anchor edges/corners. Great for badges and decorations.\n\n### Configuration\n\nThe `AnchorPopConfig` class encapsulates all popover state and configuration:\n\n```js\nconst config = new AnchorPopConfig({\n  id: 'my-popover',           // Unique identifier\n  placement: 'outside',       // Placement mode\n  position_area: 'y-end',     // CSS position-area value\n  align_self: 'start',        // Block axis alignment\n  justify_self: 'anchor-center', // Inline axis alignment\n  offset: 16,                 // Distance from anchor (px)\n  arrow_color: '#000000',     // Arrow color\n  arrow_stroke_width: 2,      // Arrow thickness (px)\n  flip_axis: 'all'           // Which axes can flip ('x', 'y', 'all', 'none')\n});\n```\n\n### Automatic Fallbacks\n\nWhen the popover doesn't fit in its primary position, AnchorPop automatically tries fallback positions:\n\n```js\n// Enable fallbacks on all axes\nconst config = new AnchorPopConfig({\n  flip_axis: 'all'  // default\n});\n\n// Restrict to vertical flipping only\nconst config = new AnchorPopConfig({\n  flip_axis: 'y'\n});\n\n// Disable fallbacks\nconst config = new AnchorPopConfig({\n  flip_axis: 'none'\n});\n```\n\n### Arrows\n\nVisual arrows connect the popover to its anchor. You can pass any clip-path compatible vector to `shape` for the arrow heads:\n\n```js\nconst config = new AnchorPopConfig({\n  arrow_color: '#000000',\n  arrow_stroke_width: 2,\n  arrow_heads: {\n    start: { show: true, shape: 'polygon(0% 0%, 100% 50%, 0% 100%)' },\n    end: { show: true, shape: 'polygon(0% 0%, 100% 50%, 0% 100%)' }\n  }\n});\n```\n\n\u003e Arrows are only shown for `outside` placement mode.\n\n## Common Patterns\n\n### Tooltip\n\n```js\nconst tooltip = AnchorPopConfig.tooltip_bottom({ offset: 8 });\n```\n\n### Dropdown Menu\n\n```js\nconst dropdown = AnchorPopConfig.dropdown({ offset: 4 });\n```\n\n### Sidebar\n\n```js\nconst sidebar = AnchorPopConfig.sidebar({ \n  side: 'right',\n  offset: 0 \n});\n```\n\n## Components\n\n### `\u003cAnchorPop\u003e`\n\nThe main popover component. Renders content in the browser's top layer using the Popover API.\n\n**Props:**\n- `id` – Unique identifier (required)\n- `from_anchor` – Anchor name of the trigger element\n- `to_anchor` – Anchor name for this popover\n- `placement` – Placement mode\n- `position_area` – CSS position-area value\n- `align_self` – Block axis alignment\n- `justify_self` – Inline axis alignment\n- `offset` – Distance from anchor in pixels\n- `flip_axis` – Which axes can flip\n- `fallback_chain` – Computed fallback positions\n- `mode` – Popover mode ('auto' or 'manual')\n- `backdrop` – Show backdrop overlay\n\n### `\u003cAnchorArrow\u003e`\n\nVisual arrow connecting the popover to the anchor. Uses pure CSS positioning with automatic updates.\n\n**Props:**\n- `id` – Unique identifier (required)\n- `from_anchor` – Anchor name of the source\n- `to_anchor` – Anchor name of the target\n- `placement` – Placement mode\n- `position_area` – CSS position-area value\n- `align_self` – Block axis alignment\n- `justify_self` – Inline axis alignment\n- `fallback_chain` – Computed fallback positions\n- `arrow_color` – Arrow color\n- `arrow_stroke_width` – Arrow thickness\n- `arrow_heads` – Arrow head configuration\n\n### `AnchorPopConfig`\n\nConfiguration class with reactive state using Svelte 5 runes.\n\n**Methods:**\n- `new AnchorPopConfig(options)` – Create a new configuration\n- `AnchorPopConfig.tooltip_top(options)` – Tooltip preset (top)\n- `AnchorPopConfig.tooltip_bottom(options)` – Tooltip preset (bottom)\n- `AnchorPopConfig.dropdown(options)` – Dropdown menu preset\n- `AnchorPopConfig.sidebar(options)` – Sidebar preset\n\n## Safari Compatibility\n\nSafari has a limitation where CSS anchor positions don't update when the anchor element is moved using `transform`. To ensure compatibility:\n\n**❌ Don't use transforms for positioning:**\n```svelte\n\u003cbutton style=\"transform: translate(100px, 50px)\"\u003e\n```\n\n**✅ Use layout positioning instead:**\n```svelte\n\u003cbutton style=\"position: relative; left: 100px; top: 50px\"\u003e\n```\n\nThis affects draggable triggers or any dynamically positioned anchors.\n\n## Advanced Usage\n\n### Custom Styling\n\nOverride CSS variables to customize appearance:\n\n```css\n:global(.popover) {\n  --popover-background: oklch(100% 0 0 / 0.95);\n  --popover-border-color: oklch(90% 0 0);\n  --popover-border-width: 1px;\n  --popover-border-radius: 8px;\n  --popover-shadow: 0 4px 16px oklch(0% 0 0 / 0.1);\n  --popover-transition-duration: 80ms;\n  --popover-animation-distance: 8px;\n}\n```\n\n### Manual Control\n\nUse `mode=\"manual\"` for programmatic control:\n\n```svelte\n\u003cscript\u003e\n  let popover_ref;\n  \n  function open_popover() {\n    popover_ref?.showPopover();\n  }\n  \n  function close_popover() {\n    popover_ref?.hidePopover();\n  }\n\u003c/script\u003e\n\n\u003cAnchorPop bind:ref={popover_ref} mode=\"manual\" {...config}\u003e\n  Content\n\u003c/AnchorPop\u003e\n```\n\n## Architecture\n\nAnchorPop uses several advanced CSS techniques:\n\n1. **CSS Anchor Positioning** – Native browser API for positioning elements relative to anchors\n2. **@position-try Rules** – Declarative fallback positioning\n3. **Anchored Container Queries** – Detect which fallback is active\n4. **Scroll-driven Animations** – Pure CSS dimension measurement\n5. **Trigger Proxy Pattern** – Bridge between stacking contexts for arrows (toplayer)\n\nFor implementation details, see the component source code.\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for development guidelines.\n\n## License\n\nMIT © Johannes Mutter\n\n## Acknowledgments\n\nBuilt with Svelte 5 and inspired by the CSS Anchor Positioning specification.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohannesmutter%2Fanchorpop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohannesmutter%2Fanchorpop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohannesmutter%2Fanchorpop/lists"}