{"id":34998026,"url":"https://github.com/codemonster-ru/floater.js","last_synced_at":"2026-04-25T11:04:11.148Z","repository":{"id":276167150,"uuid":"909059220","full_name":"codemonster-ru/floater.js","owner":"codemonster-ru","description":"Open source js library to position floating elements","archived":false,"fork":false,"pushed_at":"2026-01-27T17:47:35.000Z","size":290,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-28T04:16:16.051Z","etag":null,"topics":["dom","dropdown","floating-ui","popover","positioning","tooltip","ui"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/codemonster-ru.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","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}},"created_at":"2024-12-27T16:35:43.000Z","updated_at":"2026-01-27T17:46:39.000Z","dependencies_parsed_at":null,"dependency_job_id":"223e29d7-1f45-469d-8d52-a83dea502a92","html_url":"https://github.com/codemonster-ru/floater.js","commit_stats":null,"previous_names":["codemonster-ru/monsterfloat","codemonster-ru/floater.js"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/codemonster-ru/floater.js","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codemonster-ru%2Ffloater.js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codemonster-ru%2Ffloater.js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codemonster-ru%2Ffloater.js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codemonster-ru%2Ffloater.js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/codemonster-ru","download_url":"https://codeload.github.com/codemonster-ru/floater.js/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codemonster-ru%2Ffloater.js/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28914933,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-30T12:13:43.263Z","status":"ssl_error","status_checked_at":"2026-01-30T12:13:22.389Z","response_time":66,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["dom","dropdown","floating-ui","popover","positioning","tooltip","ui"],"created_at":"2025-12-27T02:53:58.175Z","updated_at":"2026-04-25T11:04:11.141Z","avatar_url":"https://github.com/codemonster-ru.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Floater.js\n\n![npm version](https://img.shields.io/npm/v/@codemonster-ru/floater.js)\n![npm downloads](https://img.shields.io/npm/dm/@codemonster-ru/floater.js)\n![publish](https://img.shields.io/github/actions/workflow/status/codemonster-ru/floater.js/publish.yml?label=publish)\n![license](https://img.shields.io/npm/l/@codemonster-ru/floater.js)\n\nA tiny JS/TS library for positioning floating UI elements (tooltips, popovers, menus).\n\n## Install\n\n```bash\nnpm i @codemonster-ru/floater.js\n```\n\n## Usage\n\n```ts\nimport { computePosition, offset, shift, flip, arrow, autoUpdate } from '@codemonster-ru/floater.js';\n\nconst reference = document.querySelector('#reference') as HTMLElement;\nconst floating = document.querySelector('#floating') as HTMLElement;\nconst arrowEl = document.querySelector('#arrow') as HTMLElement;\n\nconst update = () =\u003e {\n    computePosition(reference, floating, {\n        placement: 'right',\n        middleware: [shift(), offset(8), arrow(arrowEl)],\n    }).then(({ x, y, middlewareData }) =\u003e {\n        floating.style.left = `${x}px`;\n        floating.style.top = `${y}px`;\n\n        if (middlewareData.arrow) {\n            arrowEl.style.left = `${middlewareData.arrow.x}px`;\n            arrowEl.style.top = `${middlewareData.arrow.y}px`;\n        }\n    });\n};\n\nconst cleanup = autoUpdate(reference, update);\nupdate();\n\n// Later: cleanup();\n```\n\n## API\n\n### computePosition(reference, floating, options?)\n\nReturns a Promise that resolves to `{ x, y, placement, middlewareData }`.\n\n- `reference`: `HTMLElement | VirtualElement`\n- `floating`: `HTMLElement`\n- `options.placement`: one of `placementTypes` (default: `bottom`)\n- `options.middleware`: array of middleware\n- `options.strategy`: `'absolute' | 'fixed'` (default: `'absolute'`)\n\n#### Stability contract\n\n- With `strategy: 'absolute'`, `x` and `y` are coordinates in the floating element's offset parent coordinate space (suitable for `style.left/top`).\n- With `strategy: 'fixed'`, `x` and `y` are viewport coordinates (suitable for `position: fixed` elements teleported to `body`).\n- Middleware runs in the order provided and can change `x`, `y`, and `placement`.\n- `middlewareData[name]` stores the final result returned by that middleware.\n- Reserved middleware names are `flip`, `offset`, `shift`, `arrow` (custom middleware with these names is ignored with a warning).\n- When `arrow(...)` is used, `middlewareData.arrow` includes:\n    - `x` / `y`: arrow coordinates relative to the floating element\n    - `baseX` / `baseY`: floating coordinates used for arrow calculation\n\n#### Fixed strategy example (teleport to body)\n\n```ts\nfloating.style.position = 'fixed';\ndocument.body.appendChild(floating);\n\n// With strategy: 'fixed', flip() checks space in viewport coordinates\n// and picks the first fitting placement (or the side with the most space).\ncomputePosition(reference, floating, {\n    placement: 'bottom',\n    strategy: 'fixed',\n    middleware: [offset(8), flip({ placements: ['bottom', 'top'] }), shift()],\n}).then(({ x, y }) =\u003e {\n    floating.style.left = `${x}px`;\n    floating.style.top = `${y}px`;\n});\n```\n\n### placementTypes\n\nArray of supported placements:\n\n```\ntop, top-start, top-end,\nright, right-start, right-end,\nbottom, bottom-start, bottom-end,\nleft, left-start, left-end\n```\n\n### offset(value)\n\nOffsets the floating element from the reference by `value` pixels.\n\n### shift(params?)\n\nKeeps the floating element inside the visible area.\n\n- `params.parent`: optional container element. If provided, clamping uses that container; otherwise it uses the scroll parent.\n\n### flip(params?)\n\nIf the placement is not visible, tries other placements.\nWhen used together with `shift()`, the fit check ignores `shift()` to avoid picking placements that only fit after shifting.\nWhen used together with `offset()`, put `offset()` before `flip()` so the fit check includes the offset.\n\n- `params.placements`: optional list of placements to try, in order. Useful to restrict flipping (e.g. only `top`/`bottom`).\n\nExample: restrict flipping to vertical directions only.\n\n```ts\ncomputePosition(reference, floating, {\n    placement: 'bottom',\n    middleware: [offset(8), flip({ placements: ['bottom', 'top'] }), shift()],\n});\n```\n\n### arrow(arrowEl)\n\nComputes arrow position and exposes it through `middlewareData.arrow`.\n\n- `middlewareData.arrow.x/y`: arrow coordinates relative to the floating element\n- `middlewareData.arrow.baseX/baseY`: floating coordinates used for arrow calculation\n\n### autoUpdate(reference, callback, floatingOrOptions?, options?)\n\nWatches scroll/resize and calls `callback`.\nReturns a cleanup function to remove listeners.\n\n#### Stability contract\n\n- By default (`animationFrame` is not enabled), listeners are attached to:\n    - all scrollable ancestors of `reference` (and optional `floating`)\n    - `window` scroll\n    - `window` resize\n    - `ResizeObserver` for `reference` and optional `floating` when available\n- Optional `animationFrame: true` switches to a per-frame update loop (useful for transform/layout-shift driven movement) and disables the event/observer watchers above.\n- Optional `maxFps` limits update frequency in animation-frame mode (for example, `maxFps: 30`). When omitted, animation-frame mode defaults to `30 FPS`.\n- In animation-frame mode, updates pause on hidden tabs and resume when the tab becomes visible.\n- The returned cleanup function removes all listeners/observers added by `autoUpdate`.\n\n### VirtualElement\n\nUse when you need a virtual reference (e.g. mouse position).\n\n```ts\nconst virtualEl: VirtualElement = {\n    offsetTop: 100,\n    offsetLeft: 200,\n    getBoundingClientRect() {\n        return {\n            x: 200,\n            y: 100,\n            width: 0,\n            height: 0,\n            top: 100,\n            right: 200,\n            bottom: 100,\n            left: 200,\n        };\n    },\n};\n```\n\n## TypeScript\n\nThe package ships with types generated at build time via `tsc`. See `index.ts` for full exports.\n\n## Migration notes (0.x -\u003e 1.0)\n\n- `autoUpdate(...)` now returns a cleanup function. Call it when the floating UI unmounts.\n- `middlewareData.arrow` now keeps arrow coordinates (`x/y`) and also exposes `baseX/baseY`.\n- Positioning and clamping behavior was hardened for scroll containers, viewport checks, and `shift + offset` interactions.\n\n## License\n\n[MIT](https://github.com/codemonster-ru/floater.js/blob/main/LICENSE)\n\n## Author\n\n[@KolesnikovKirill](https://github.com/kolesnikovKirill)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodemonster-ru%2Ffloater.js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcodemonster-ru%2Ffloater.js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodemonster-ru%2Ffloater.js/lists"}