{"id":13515915,"url":"https://github.com/alpine-collective/alpine-magic-helpers","last_synced_at":"2026-01-14T02:44:50.927Z","repository":{"id":40752625,"uuid":"287978955","full_name":"alpine-collective/alpine-magic-helpers","owner":"alpine-collective","description":"A collection of magic properties and helper functions for use with Alpine.js","archived":false,"fork":false,"pushed_at":"2023-02-03T13:32:55.000Z","size":2330,"stargazers_count":769,"open_issues_count":11,"forks_count":18,"subscribers_count":7,"default_branch":"master","last_synced_at":"2026-01-11T19:34:16.666Z","etag":null,"topics":["alpine","alpine-collective","alpinejs","magic-helper"],"latest_commit_sha":null,"homepage":"https://npmjs.com/alpine-magic-helpers","language":"JavaScript","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/alpine-collective.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":["kevinbatdorf","ryangjchandler","HugoDF","SimoTod"]}},"created_at":"2020-08-16T16:13:13.000Z","updated_at":"2026-01-10T17:22:59.000Z","dependencies_parsed_at":"2023-02-18T07:30:47.313Z","dependency_job_id":null,"html_url":"https://github.com/alpine-collective/alpine-magic-helpers","commit_stats":null,"previous_names":["kevinbatdorf/alpine-magic-helpers"],"tags_count":21,"template":false,"template_full_name":"KevinBatdorf/alpine-plugin-template","purl":"pkg:github/alpine-collective/alpine-magic-helpers","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alpine-collective%2Falpine-magic-helpers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alpine-collective%2Falpine-magic-helpers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alpine-collective%2Falpine-magic-helpers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alpine-collective%2Falpine-magic-helpers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alpine-collective","download_url":"https://codeload.github.com/alpine-collective/alpine-magic-helpers/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alpine-collective%2Falpine-magic-helpers/sbom","scorecard":{"id":186749,"data":{"date":"2025-08-11","repo":{"name":"github.com/alpine-collective/alpine-magic-helpers","commit":"426a27d8a22292c278091cd409fc53941f5a899b"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.4,"checks":[{"name":"Code-Review","score":4,"reason":"Found 8/18 approved changesets -- score normalized to 4","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Pinned-Dependencies","score":4,"reason":"dependency not pinned by hash detected -- score normalized to 4","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish-to-npm.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/alpine-collective/alpine-magic-helpers/publish-to-npm.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish-to-npm.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/alpine-collective/alpine-magic-helpers/publish-to-npm.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/publish-to-npm.yml:28: update your workflow using https://app.stepsecurity.io/secureworkflow/alpine-collective/alpine-magic-helpers/publish-to-npm.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/publish-to-npm.yml:71: update your workflow using https://app.stepsecurity.io/secureworkflow/alpine-collective/alpine-magic-helpers/publish-to-npm.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/run-tests.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/alpine-collective/alpine-magic-helpers/run-tests.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/run-tests.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/alpine-collective/alpine-magic-helpers/run-tests.yml/master?enable=pin","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   2 third-party GitHubAction dependencies pinned","Info:   2 out of   2 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/publish-to-npm.yml:1","Warn: no topLevel permission defined: .github/workflows/run-tests.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.md:0","Info: FSF or OSI recognized license: MIT License: LICENSE.md:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 23 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"43 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-cph5-m8f7-6c5x","Warn: Project is vulnerable to: GHSA-wf5p-g6vw-rhxx","Warn: Project is vulnerable to: GHSA-jr5f-v2jv-69x6","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-pxg6-pf52-xh8x","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-r7jx-5m6m-cpg9","Warn: Project is vulnerable to: GHSA-j4f2-536g-r55m","Warn: Project is vulnerable to: GHSA-r7qp-cfhv-p84w","Warn: Project is vulnerable to: GHSA-jchw-25xp-jwwc","Warn: Project is vulnerable to: GHSA-cxjh-pqwp-8mfp","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-rc47-6667-2j5j","Warn: Project is vulnerable to: GHSA-78xj-cgh5-2h22","Warn: Project is vulnerable to: GHSA-2p57-rm9w-gvfp","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-6fx8-h7jm-663j","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-gcx4-mw62-g8wm","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-m6fv-jmcg-4jfg","Warn: Project is vulnerable to: GHSA-cm22-4g7w-348p","Warn: Project is vulnerable to: GHSA-25hc-qcg6-38wj","Warn: Project is vulnerable to: GHSA-qm95-pgcg-qqfq","Warn: Project is vulnerable to: GHSA-cqmj-92xf-r6r9","Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36","Warn: Project is vulnerable to: GHSA-4wf5-vphf-c2xc","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-fhg7-m89q-25r3","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q","Warn: Project is vulnerable to: GHSA-72mh-269x-7mh5","Warn: Project is vulnerable to: GHSA-h4j5-c7cj-74xg"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-16T19:55:57.471Z","repository_id":40752625,"created_at":"2025-08-16T19:55:57.471Z","updated_at":"2025-08-16T19:55:57.471Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28408733,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"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":["alpine","alpine-collective","alpinejs","magic-helper"],"created_at":"2024-08-01T05:01:17.359Z","updated_at":"2026-01-14T02:44:50.896Z","avatar_url":"https://github.com/alpine-collective.png","language":"JavaScript","funding_links":["https://github.com/sponsors/kevinbatdorf","https://github.com/sponsors/ryangjchandler","https://github.com/sponsors/HugoDF","https://github.com/sponsors/SimoTod"],"categories":["JavaScript","Extensions \u0026 Plugins"],"sub_categories":[],"readme":"\n[![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/alpine-collective/alpine-magic-helpers?label=version\u0026style=flat-square)](https://www.npmjs.com/package/alpine-magic-helpers)\n[![](https://data.jsdelivr.com/v1/package/gh/alpine-collective/alpine-magic-helpers/badge)](https://www.jsdelivr.com/package/gh/alpine-collective/alpine-magic-helpers)\n[![npm bundle size](https://img.shields.io/bundlephobia/minzip/alpine-magic-helpers?color=#0F0)](https://bundlephobia.com/result?p=alpine-magic-helpers)\n\n# Magic Helpers\n\nA collection of magic properties and helper functions for use with [Alpine.js](https://github.com/alpinejs/alpine) version 2\n\n:warning:  Notice: This collection of helpers will be tied to version 2 of Alpine and will only receive bug fixes and minor updates as needed.\n\n→ New features and plugins for V3 that will be found in the [toolkit repo](https://github.com/alpine-collective/toolkit).\n\n## About\n\nAdds the following magic helpers to use with Alpine JS.\n| Magic Helpers | Description |\n| --- | --- |\n| [`$component/$parent`](#component) | Natively access and update data from other components or the parent component. |\n| [`$fetch/$get/$post`](#fetch) | Using Axios, fetch JSON from an external source.  |\n| [`$interval`](#interval) | Run a function every n milliseconds. Optionally start and stop the timer. |\n| [`$range`](#range) | Iterate over a range of values. |\n| [`$refresh`](#refresh) | Manually refresh a component. |\n| [`$screen`](#screen) | Detect if the current browser width is equal or greater than a given breakpoint. |\n| [`$scroll`](#scroll) | Scroll the page vertically to a specific position. |\n| [`$truncate`](#truncate) |  Limit a text string to a specific number of characters or words. |\n| [`$undo`](#undo) |  Track and undo state changes inside your component. |\n\nAdds the following custom directives to use with Alpine JS.\n| Custom Directives | Description |\n| --- | --- |\n| [`x-unsafe-html`](#x-unsafe-html) | like x-html but allowing new javascript scripts to run. |\n\n ***More to come!***\n\n🚀 If you have ideas for more magic helpers or custom directives, please open a [discussion](https://github.com/alpine-collective/alpine-magic-helpers/discussions) or join us on the [AlpineJS Discord](https://discord.gg/snmCYk3)\n\n**Known issues**\n* [Using `$component`/`$parent` in `x-init`](#warning-using-componentparent-in-x-init)\n* [Using Magic Helpers with Livewire](#warning-using-magic-helpers-with-livewire)\n\n## Installation\n\nInclude the following `\u003cscript\u003e` tag in the `\u003chead\u003e` of your document before Alpine:\n\n```html\n\u003cscript src=\"https://cdn.jsdelivr.net/gh/alpine-collective/alpine-magic-helpers@1.2.x/dist/index.min.js\" defer\u003e\u003c/script\u003e\n```\n\nOr you can use the specific magic helpers you need:\n\n```html\n\u003cscript src=\"https://cdn.jsdelivr.net/gh/alpine-collective/alpine-magic-helpers@1.2.x/dist/component.min.js\" defer\u003e\u003c/script\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/gh/alpine-collective/alpine-magic-helpers@1.2.x/dist/fetch.min.js\" defer\u003e\u003c/script\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/gh/alpine-collective/alpine-magic-helpers@1.2.x/dist/interval.min.js\" defer\u003e\u003c/script\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/gh/alpine-collective/alpine-magic-helpers@1.2.x/dist/range.min.js\" defer\u003e\u003c/script\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/gh/alpine-collective/alpine-magic-helpers@1.2.x/dist/refresh.min.js\" defer\u003e\u003c/script\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/gh/alpine-collective/alpine-magic-helpers@1.2.x/dist/screen.min.js\" defer\u003e\u003c/script\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/gh/alpine-collective/alpine-magic-helpers@1.2.x/dist/scroll.min.js\" defer\u003e\u003c/script\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/gh/alpine-collective/alpine-magic-helpers@1.2.x/dist/truncate.min.js\" defer\u003e\u003c/script\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/gh/alpine-collective/alpine-magic-helpers@1.2.x/dist/undo.min.js\" defer\u003e\u003c/script\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/gh/alpine-collective/alpine-magic-helpers@1.2.x/dist/unsafeHTML.min.js\" defer\u003e\u003c/script\u003e\n```\n\n---\n\n### Manual\n\nIf you wish to create your own bundle:\n\n```bash\nnpm install alpine-magic-helpers --save\n```\n\nThen add the following to your script:\n\n```javascript\nimport 'alpine-magic-helpers'\nimport 'alpinejs'\n```\n\nOr you can import the specific magic helpers you need like so:\n\n```javascript\nimport 'alpine-magic-helpers/dist/component'\nimport 'alpine-magic-helpers/dist/fetch'\nimport 'alpinejs'\n```\n\n---\n\n### :warning: **Using Magic Helpers with Livewire**\nWhen using magic helpers along with Laravel Livewire, you need to make sure that the library is registered after Livewire to prevent Livewire from overriding the magic helper startup callbacks. This can be done either using the defer attribute on the magic helper script or including the magic helper script at the bottom of your body after `@livewireScripts` **without** the `defer` attribute.\n\n---\n\n### `$component`\n**Example:**\n\nArguably more useful, this also adds a `$parent` magic helper to access parent data\n```html\n\u003cdiv x-data=\"{ color: 'blue' }\"\u003e\n    \u003cp x-data x-text=\"$parent.color\"\u003e\u003c/p\u003e\n    \u003c!-- The text will say blue --\u003e\n\u003c/div\u003e\n```\n[Demo](https://codepen.io/KevinBatdorf/pen/XWdjWrr)\n\nYou may watch other components, but you must give them each an id using the 'id' attribute or `x-id` if you need more flexibility:\n```html\n\u003cdiv x-data=\"{ color: 'blue' }\"\u003e\n    \u003cp\n        x-data\n        x-text=\"$component('yellowSquare').color\"\n        :class=\"`text-${$parent.color}-700`\"\u003e\n        \u003c!-- This text will have blue background color and the text will say yellow --\u003e\n    \u003c/p\u003e\n\u003c/div\u003e\n\n\u003cdiv x-id=\"yellowSquare\" x-data=\"{ color: 'yellow' }\"\u003e\u003c/div\u003e\n```\n\n#### :warning: **Using `$component`/`$parent` in `x-init`**\n```html\n \u003c!-- This won't populate baz correctly --\u003e\n \u003cdiv x-data=\"{ foo: 'bar' }\"\u003e\n   \u003cdiv x-data=\"{ baz: null }\" x-init=\"() =\u003e baz = $parent.foo\"\u003e\n     \u003cspan x-text='baz'\u003e\u003c/span\u003e\n   \u003c/div\u003e\n \u003c/div\u003e\n \u003c!-- use this instead --\u003e\n \u003cdiv x-data=\"{ foo: 'bar' }\"\u003e\n   \u003cdiv x-data=\"{ baz: null }\" x-init=\"$nextTick(() =\u003e baz = $parent.foo)\"\u003e\n     \u003cspan x-text='baz'\u003e\u003c/span\u003e\n   \u003c/div\u003e\n \u003c/div\u003e\n \u003c!-- or --\u003e\n \u003cdiv x-data=\"{ foo: 'bar' }\"\u003e\n   \u003cdiv x-data=\"{ baz: null }\" x-init=\"setTimeout(() =\u003e baz = $parent.foo)\"\u003e\n     \u003cspan x-text='baz'\u003e\u003c/span\u003e\n   \u003c/div\u003e\n \u003c/div\u003e\n```\nWhen a component is initialised, the observed component may not be ready yet due to the way Alpine starts up. This is always true for `$parent` and it occurs for `$component` when the observer is placed before the observed component in the page structure.\nPrevious versions were using a hack to evaluate the missing x-data on the fly but that strategy wasn't allowing to use nested magic properties and it was not syncronising properly in some edge cases.\nThe magic helper since version 1.0 defers the resolution of those properties (resolving temporary to empty strings/noop functions) until the observed component is ready and then refreshes the component: this happens in a few milliseconds and it's not noticable by the final users but refreshing a component won't rerun `x-init` with the correct values.\n**If developers need to use the magic property inside x-init, they'll need to manually postpone the execution of x-init for one tick either using the Alpine native `$nextTick` or a setTimeout with no duration (See examples above).**\n\n---\n\n### `$fetch`\n**Example:**\n```html\n\u003cdiv x-data=\"{ url: 'https://jsonplaceholder.typicode.com/todos/1' }\"\n    x-init=\"$fetch(url).then(data =\u003e console.log(data))\"\u003e\n    \u003c!-- After init, data will be logged to the console --\u003e\n\u003c/div\u003e\n```\n[Demo](https://codepen.io/KevinBatdorf/pen/poyyXKj)\n\n\u003e As a shortcut, you can optionally use `$get(url, params)` or `$post(url, data)` to conveniently send a GET or POST request with params or data as the second argument.\n\n**Optionally pass in an Axios options object**\n\nIf you need more control, you may pass in an object to customize the request [See all options](https://github.com/axios/axios).\n\n**Example:**\n\n```html\n\u003cdiv x-data=\"{ url: 'https://jsonplaceholder.typicode.com/todos/1' }\"\n    x-init=\"$fetch({ url: url, method: 'post' }).then(({ data }) =\u003e console.log(data))\"\u003e\n\u003c/div\u003e\n```\n\u003e Note that this will return the entire response object, whereas by default `$fetch` will only return the data\n\n---\n\n### `$interval`\n**Example:**\n```html\n\u003cdiv\n    x-data=\"{\n        timer: 500,\n        functionToRun: function() {\n            console.log('Hello console')\n        }\n    }\"\n    x-init=\"$interval(functionToRun, timer)\"\u003e\n\u003c/div\u003e\n```\n[Demo](https://codepen.io/KevinBatdorf/pen/xxVVoaX?editors=1010)\n\n**Optionally pass in options**\n\nBy default, `$interval ` will run your function every `nth` millisecond when browser provides an animation frame (via `requestAnimationFrame`). This means that the function will not run if the browser tab is not visible. Optionally, you may pass in the following options as the second parameter:\n| Property | Description |\n| --- | --- |\n| `timer` | Timer in milliseconds.  |\n| `delay` | Delay the first run. N.B. The first run is also delayed by the timer time. |\n| `forceInterval` |  Ignore the browser animation request mechanism. Default is false |\n\n\u003e ⚠️ We also add a hidden property `autoIntervalTest` that will clear/stop the timer if set to false, and start the timer if then set to true.\n\n**Example:**\n\n```html\n\u003cdiv\n    x-data=\"{\n        timer: 500,\n        autoIntervalTest: true, // optional to start/stop the timer\n        funtionToRun: function() {\n            console.log('Hi again!')\n        }\n    }\"\n    x-init=\"$interval(funtionToRun, { timer: 1000, delay: 5000, forceInterval: true })\"\u003e\n    \u003cbutton\n        @click=\"autoIntervalTest = !autoIntervalTest\"\n        x-text=\"autoIntervalTest ? 'pause' : 'play'\"\u003e\u003c/button\u003e\n\u003c/div\u003e\n```\n[Demo](https://codepen.io/KevinBatdorf/pen/poyyXQy?editors=1010)\n\n---\n\n### `$range`\n**Example:**\n\nThe `$range` helper mostly mimics implementations found in other languages `$range(start, stop, step = 1)`\n```html\n\u003cdiv x-data\u003e\n    \u003ctemplate x-for=\"item in $range(1, 5)\"\u003e\n        ...\n    \u003c/template\u003e\n\u003c/div\u003e\n\u003c!-- This will output 5 iterations [1, 2, 3, 4, 5], modelled after PHP's implimentation of range() --\u003e\n```\n[Demo](https://codepen.io/KevinBatdorf/pen/vYKbPBd)\n\n\u003e N.B: You may use `$range(10)` which will compute to `[1...10]`\n\n---\n\n\n### `$refresh`\n**Example:**\n```html\n\u003cdiv x-data\u003e\n    \u003cbutton @click=\"$refresh()\"\u003eRefresh \u003ccode\u003eDate.now()\u003c/code\u003e\u003c/button\u003e\n    \u003cspan x-text=\"Date.now()\"\u003e\u003c/span\u003e\n\u003c/div\u003e\n```\n[Demo](https://codepen.io/KevinBatdorf/pen/PobZjrz?editors=1000)\n\n---\n### `$screen`\n**Example:**\n\nThe `$screen` helper detects if the current browser width is equal or greater than a given breakpoint and returns `true` or `false` based on the result.\n\n```html\n\u003cdiv x-data\u003e\n    \u003cspan x-show=\"$screen('lg')\"\u003eThis will be visible if the window width is equal or greater than 1024px.\u003c/span\u003e\n\u003c/div\u003e\n```\n\n*By default the `$screen` helper uses the following endpoint borrowed by **Tailwind CSS**:*\n- `xs`: 0px\n- `sm`: 640px\n- `md`: 768px\n- `lg`: 1024px\n- `xl`: 1280px\n- `2xl`: 1536px\n\n\u003e ⚠️ **NOTE**: A single breakpoint is only going to tell you if the browser width is equal or greater than the given breakpoint. If you want to restrict the check to a specific range, you will need to negate the next endpoint as:\n\n```html\n\u003cdiv x-data\u003e\n    \u003cspan x-show=\"$screen('md') \u0026\u0026 !$screen('lg')\"\u003eThis will be visible if screen width is equal or greater than 768px but smaller then 1024px.\u003c/span\u003e\n\u003c/div\u003e\n```\n\n**Custom breakpoints**\n\nYou can pass a numeric value to use an ad-hoc breakpoint.\n```html\n\u003cdiv x-data\u003e\n    \u003cspan x-show=\"$screen(999)\"\u003eThis will be visible if screen width is equal or greater than 999px.\u003c/span\u003e\n\u003c/div\u003e\n```\n\nYou can also override the default breakpoints including the following `\u003cscript\u003e` tag in the `\u003chead\u003e` of your document\n\n```html\n\u003c!-- this example uses Bulma's breakpoints. --\u003e\n\u003cscript\u003e\n    window.AlpineMagicHelpersConfig = {\n        breakpoints: {\n            mobile: 0,\n            tablet: 769,\n            desktop: 1024,\n            widescreen: 1216,\n            fullhd: 1408\n        }\n    }\n\u003c/script\u003e\n```\nAnd using those breakpoints in your page.\n```html\n\u003cdiv x-data\u003e\n    \u003cspan x-show=\"$screen('tablet')\"\u003eThis will be visible if screen width is equal or greater than 769px.\u003c/span\u003e\n\u003c/div\u003e\n```\n\n[Demo](https://codepen.io/KevinBatdorf/pen/OJXKRXE?editors=1000)\n\n---\n\n### `$scroll`\n**Example:**\n```html\n\u003cdiv x-data\u003e\n    \u003cdiv x-ref=\"foo\"\u003e\n        ...\n    \u003c/div\u003e\n    \u003cbutton x-on:click=\"$scroll($refs.foo)\"\u003eScroll to foo\u003c/button\u003e\n\u003c/div\u003e\n```\n[Demo](https://codepen.io/KevinBatdorf/pen/PozVLPy?editors=1000)\n\nAlternatively, you can pass a css selector to scroll to an element at any position.\n```html\n\u003cdiv id=\"foo\"\u003e\n\u003c/div\u003e\n\u003cdiv x-data\u003e\n    \u003cbutton x-on:click=\"$scroll('#foo')\"\u003eScroll to #foo\u003c/button\u003e\n\u003c/div\u003e\n```\n\n`$scroll` also supports integers to scroll to a specific point of the page.\n```html\n\u003cbutton x-data x-on:click=\"$scroll(0)\"\u003eScroll to top\u003c/button\u003e\n```\n[Demo](https://codepen.io/KevinBatdorf/pen/PozVLPy?editors=1000) (same as above)\n\n`$scroll` optionally supports a second parameter where it's possible to define the behavior mode, `auto|smooth` (default smooth):\n```html\n\u003cdiv x-data\u003e\n    \u003cdiv x-ref=\"foo\"\u003e\n        ...\n    \u003c/div\u003e\n    \u003cbutton x-on:click=\"$scroll($refs.foo, {behavior: 'auto'})\"\u003eJump to foo\u003c/button\u003e\n\u003c/div\u003e\n...\n\u003cdiv id=\"foo\"\u003e\n\u003c/div\u003e\n\u003cdiv x-data\u003e\n    \u003cbutton x-on:click=\"$scroll('#foo', {behavior: 'auto'})\"\u003eJump to #foo\u003c/button\u003e\n\u003c/div\u003e\n...\n\u003cbutton x-data x-on:click=\"$scroll(0, {behavior: 'auto'})\"\u003eJump to top\u003c/button\u003e\n```\nWith offset:\n```html\n\u003cdiv x-data\u003e\n    \u003cdiv x-ref=\"foo\"\u003e\n        ...\n    \u003c/div\u003e\n    \u003cbutton x-on:click=\"$scroll($refs.foo, {offset: 50})\"\u003eScroll to 50px before foo\u003c/button\u003e\n\u003c/div\u003e\n...\n\u003cdiv id=\"foo\"\u003e\n\u003c/div\u003e\n\u003cdiv x-data\u003e\n    \u003cbutton x-on:click=\"$scroll('#foo', {offset: 50})\"\u003eScroll to 50px before #foo\u003c/button\u003e\n\u003c/div\u003e\n...\n\u003cbutton x-data x-on:click=\"$scroll(0, {offset: 50})\"\u003eJump to 50px before top (a bit daft but supported)\u003c/button\u003e\n```\nWith both:\n```html\n\u003cdiv x-data\u003e\n    \u003cdiv x-ref=\"foo\"\u003e\n        ...\n    \u003c/div\u003e\n    \u003cbutton x-on:click=\"$scroll($refs.foo, {behavior: 'auto', offset: 50})\"\u003eJump to 50px before foo\u003c/button\u003e\n\u003c/div\u003e\n...\n\u003cdiv id=\"foo\"\u003e\n\u003c/div\u003e\n\u003cdiv x-data\u003e\n    \u003cbutton x-on:click=\"$scroll('#foo', {behavior: 'auto', offset: 50})\"\u003eJump to 50px before #foo\u003c/button\u003e\n\u003c/div\u003e\n...\n\u003cbutton x-data x-on:click=\"$scroll(0, {behavior: 'auto', offset: 50})\"\u003eJump to 50px before top\u003c/button\u003e\n```\n[Demo](https://codepen.io/KevinBatdorf/pen/PozVLPy?editors=1000) (same as above)\n\n---\n\n### `$truncate`\n**Example:**\n```html\n\u003cdiv\n    x-data=\"{ characters: 50, string: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'}\"\n    x-text=\"$truncate(string, characters)\"\n    @click=\"characters = undefined\"\u003e\n    \u003c!-- Text will show 'Lorem ipsum dolor sit amet, consectetur adipiscing…' and will reveal all when clicked--\u003e\n\u003c/div\u003e\n```\nYou may also pass a third argument to change the string that will be appended to the end:\n```html\n\u003cdiv\n    x-data=\"{ characters: 50, string: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'}\"\n    x-text=\"$truncate(string, characters, ' (...)')\"\u003e\n    \u003c!-- Text will show 'Lorem ipsum dolor sit amet, consectetur adipiscing (...)' --\u003e\n\u003c/div\u003e\n```\n[Demo](https://codepen.io/KevinBatdorf/pen/BaKKgGg?editors=1000)\n\n**Optionally pass in options**\n\nBy default, `$truncate` will return take characters as a parameter. Instead you can pass in an object and trim by words. You may also update the ellipsis.\n\n**Example:**\n\n```html\n\u003cdiv\n    x-data=\"{ count: 5, string: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'}\"\n    x-text=\"$truncate(string, { words: words, ellipsis: ' ...read more' })\"\n    @click=\"count = 0\"\u003e\n    \u003c!-- Will start with 5 words, then increase to unlimited when clicked --\u003e\n\u003c/div\u003e\n```\n[Demo](https://codepen.io/KevinBatdorf/pen/BaKKgGg?editors=1000) (same as above)\n\u003e Behind the scenes, for words, this uses `sentence.split(\" \").splice(0, words).join(\" \")` which does not define a word in all languages.\n\n---\n### `$undo`\n**Example:**\n```html\n\u003cdiv x-data=\"{ number: 0 }\" x-init=\"$track()\"\u003e\n    \u003cbutton @click=\"number = Math.floor(Math.random() * 10)\" x-text=\"number\"\u003e\u003c/button\u003e\n    \u003cbutton x-show=\"$history.length\" @click=\"$undo()\"\u003eundo\u003c/button\u003e\n\u003c/div\u003e\n```\n[Demo](https://codepen.io/KevinBatdorf/pen/jOrVzOg?editors=1000)\n\nThe `$undo` helper actually involves three helpers in one. First, add the `$track()` helper to the `x-init` directive to start tracking the component state. Next, add a button to `$undo()` changes as needed. And finally, you can access whether changes have occurred by using `$history.length`.\n\n**Optionally pass in options**\n\nBy default, `$undo` will track all properties. Optionally you may limit the properties by passing in a string with the property name, or an array of property names.\n\n**Example:**\n\n```html\n\u003cdiv x-data=\"{ number: 0; another: 0 }\" x-init=\"$track('number')\"\u003e\n    \u003cbutton @click=\"number = number + 1\" x-text=\"number\"\u003e\u003c/button\u003e\n    \u003cbutton @click=\"another = another + 1\" x-text=\"another\"\u003e\u003c/button\u003e\n    \u003cbutton x-show=\"$history.length\" @click=\"$undo()\"\u003eundo number only\u003c/button\u003e\n\u003c/div\u003e\n```\n\u003e Use `$track(['prop1', 'prop2'])` to track multiple properties\n\n[Demo](https://codepen.io/KevinBatdorf/pen/VwjmXLy?editors=1000)\n\n---\n### `x-unsafe-html`\n**Example:**\n```html\n\u003cdiv x-data=\"{ foo: bar }\"\u003e\n    \u003cdiv x-unsafe-html=\"foo\"\u003e\u003c/div\u003e\n    \u003cbutton @click=\"foo = '\u003cp\u003ebar\u003c/p\u003e\u003cscript\u003ealert(1)\u003c/script\u003e'\"\u003etest\u003c/button\u003e\n\u003c/div\u003e\n```\n\n\u003e :warning: **Only use on trusted content.** :warning:\n\u003e\n\u003e Dynamically rendering HTML from third parties can easily lead to [XSS](https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting) vulnerabilities.\n\n[Demo](https://codepen.io/KevinBatdorf/pen/poNYpZb)\n\n---\n\n## License\n\nCopyright (c) 2020 Alpine Collective\n\nLicensed under the MIT license, see [LICENSE.md](LICENSE.md) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falpine-collective%2Falpine-magic-helpers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falpine-collective%2Falpine-magic-helpers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falpine-collective%2Falpine-magic-helpers/lists"}