{"id":23248243,"url":"https://github.com/devhammed/wickedstate","last_synced_at":"2025-08-20T07:31:11.804Z","repository":{"id":80239366,"uuid":"601921105","full_name":"devhammed/wickedstate","owner":"devhammed","description":"Experimenting with a simple JavaScript UI library.","archived":false,"fork":false,"pushed_at":"2024-08-18T23:00:56.000Z","size":232,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-08-19T00:19:44.469Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devhammed.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2023-02-15T05:30:22.000Z","updated_at":"2024-08-19T00:19:44.547Z","dependencies_parsed_at":"2024-07-06T11:49:43.074Z","dependency_job_id":"88843c2a-246f-4012-9352-c7f2ad85e4db","html_url":"https://github.com/devhammed/wickedstate","commit_stats":null,"previous_names":["devhammed/wickedstate"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devhammed%2Fwickedstate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devhammed%2Fwickedstate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devhammed%2Fwickedstate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devhammed%2Fwickedstate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devhammed","download_url":"https://codeload.github.com/devhammed/wickedstate/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230400625,"owners_count":18219832,"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","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":[],"created_at":"2024-12-19T08:12:57.057Z","updated_at":"2025-08-20T07:31:11.787Z","avatar_url":"https://github.com/devhammed.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# wickedstate\n\nA plug-n-play reactive library for building web applications.\n\n## Installation\n\n### Using CDN\n\nUsing a CDN is the easiest way to get started with the library. You can include the following script tag in your HTML file to get started:\n\n```html\n\u003c!doctype html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n    \u003cmeta charset=\"UTF-8\" /\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /\u003e\n    \u003ctitle\u003eMy Wicked App\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\u003cdiv *state=\"{ count: 0 }\"\u003e\n    \u003ch1 *text=\"count\"\u003e\u003c/h1\u003e\n    \u003cbutton *on[click]=\"count++\" type=\"button\"\u003eIncrement\u003c/button\u003e\n    \u003cbutton *on[click]=\"count--\" type=\"button\"\u003eDecrement\u003c/button\u003e\n\u003c/div\u003e\n\u003cscript type=\"module\"\u003e\n    import { render } from 'https://esm.sh/wickedstate@0.1.5';\n\n    render(document.body).then(() =\u003e {\n        console.log('App is ready');\n    });\n\u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\nWe are using [esm.sh](https://esm.sh) CDN in the example above, you can replace it with any other CDN of your choice that supports ES Modules e.g `https://cdn.skypack.dev/wickedstate@0.1.5`.\n\n### Using Vite\n\nIf you don't have a Vite project already, you can create a new project with the package manager of your choice using the following commands:\n\n- NPM: `npm create vite@latest my-wicked-app -- --template vanilla-ts`\n- Yarn: `yarn create vite my-wicked-app --template vanilla-ts`\n- PNPM: `pnpm create vite my-wicked-app --template vanilla-ts`\n- BUN: `bun create vite my-wicked-app --template vanilla-ts`\n- Deno: `deno run -A npm:create-vite@latest --template vanilla-ts my-wicked-app`\n\nYou can replace `my-wicked-app` with the name of your project and also replace `vanilla-ts` with `vanilla` if you prefer JavaScript.\n\nThen navigate to the project directory:\n\n```bash\ncd my-wicked-app\n```\n\nThen install the library using the package manager of your choice:\n\n- NPM: `npm install wickedstate`\n- Yarn: `yarn add wickedstate`\n- PNPM: `pnpm add wickedstate`\n- BUN: `bun add wickedstate`\n- Deno: `deno add jsr:@devhammed/wickedstate`\n\nAnd open `src/main.ts` in your editor and replace the content with the following:\n\n```ts\nimport { render } from 'wickedstate';\n\nrender(document.body).then(() =\u003e {\n  console.log('App is ready');\n});\n```\n\nThen open the `index.html` file and replace the content with the following:\n\n```html\n\u003c!doctype html\u003e\n\u003chtml lang=\"en\"\u003e\n  \u003chead\u003e\n    \u003cmeta charset=\"UTF-8\" /\u003e\n    \u003clink rel=\"icon\" type=\"image/svg+xml\" href=\"/vite.svg\" /\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /\u003e\n    \u003ctitle\u003eVite + TS\u003c/title\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003cdiv *state=\"{ count: 0 }\"\u003e\n        \u003ch1 *text=\"count\"\u003e\u003c/h1\u003e\n        \u003cbutton *on[click]=\"count++\" type=\"button\"\u003eIncrement\u003c/button\u003e\n        \u003cbutton *on[click]=\"count--\" type=\"button\"\u003eDecrement\u003c/button\u003e\n    \u003c/div\u003e\n    \u003cscript type=\"module\" src=\"/src/main.ts\"\u003e\u003c/script\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\nAnd then run the following command to start the development server:\n\n```bash\nnpm run dev\n```\n\nGo to `http://localhost:5173` in your browser to see the app in action.\n\n## Directives\n\nA directive is a special HTML attribute that is recognized by the library which instructs it what to do with the element.\n\nThe syntax for a directive is `\u003ctag *name[type].modifiers[value]=\"expression\" /\u003e` where:\n\n- `tag` is the HTML tag name e.g. `div`, `button`, `input`, etc.\n- `name` is the name of the directive e.g. `state`, `on`, `text`, etc.\n- `type` serves as an identifier for the directive, and it is optional but some directives like `on` requires it to differentiate between different events e.g `*on[click]`, `*on[submit]`, etc.\n- `modifiers` are used to modify the behavior of the directive, you can repeat modifiers but not on the same directive e.g. `*on[click].once`, `*on[click].prevent`, `*on[click].once.prevent`, etc.\n- `value` is the value of a modifier for the ones that requires it e.g. `*on[input].debounce[500ms]`, `*on[resize].window.debounce[300ms]`, etc.\n- `expression` is the attribute value that will be evaluated as a JavaScript expression e.g. `*state=\"{ count: 0 }\"`, `*on[click]=\"count++\"`, etc.\n\nYou can also notice that the directive is prefixed with an asterisk `*` to differentiate it from a regular HTML attribute.\n\nNow let's take a look at the available built-in directives:\n\n### `state`\n\nDeclares a component and its data for a block of HTML elements.\n\n```html\n\u003cdiv *state=\"{ count: 0 }\"\u003e\n    ...\n\u003c/div\u003e\n```\n\n### Reusing State\n\nYou can reuse a state object across multiple elements by using the `data` function exported from the library.\n\n```js\nimport { data, render } from 'wickedstate';\n\ndata('postItem', (id) =\u003e ({\n    id,\n    postData: null,\n    init() {\n        // Fetch post from server\n    },\n    like() {\n        // like post\n    },\n    unlike() {\n        // unlike post\n    },\n}));\n\nrender(document.body).then(() =\u003e {\n    console.log('App is ready');\n});\n```\n\nThen call the name of the state object in the `*state` directive like a function (this allows you to pass arguments to the state object).\n\n```html\n\u003cdiv *state=\"{ postIds: [1, 2, 3, 4] }\"\u003e\n    \u003ctemplate *for=\"id in postIds : id\"\u003e\n        \u003cdiv *state=\"postItem(id)\"\u003e\n            ...\n        \u003c/div\u003e\n    \u003c/template\u003e\n\u003c/div\u003e\n```\n\n### Lifecycle Hooks\n\nYou can also define lifecycle hooks for your state object by adding the following methods:\n\n- `init` - Called when the state object is initialized.\n- `destroy` - Called when the state object is destroyed.\n\nBelow is a timer example that increments a counter every second and clears the interval when the component is destroyed:\n\n```html\n\u003cdiv\n    *state=\"{\n        count: 0,\n        interval: null,\n        init() {\n            this.interval = setInterval(() =\u003e {\n                this.count++;\n            }, 1000);\n        },\n        destroy() {\n            clearInterval(this.interval);\n        }\n    }\"\n\u003e\n    \u003ch1 *text=\"count\"\u003e\u003c/h1\u003e\n\u003c/div\u003e\n```\n\n### Single-element States\n\nThis library also supports single-element states, which means you can declare a state object for a single element and also use other directives right on the element.\n\n```html\n    \u003cbutton *state=\"{ label: 'Click Here' }\" *text=\"label\" *on[click]=\"alert('Clicked')\"\u003e\u003c/button\u003e\n```\n\n### `on`\n\nListen for browser events on an element\n\n```html\n\u003cbutton *on[click]=\"count++\" type=\"button\"\u003eIncrement\u003c/button\u003e\n```\n\nIf you wish to access the native JavaScript event object from your expression, you can use `$event` magic property:\n\n```html\n\u003cinput *on[input]=\"console.log($event.target.value)\" type=\"text\" /\u003e\n```\n\nThe `on` directive also supports the following modifiers:\n\n#### `once`\n\nListen to the event only once.\n\n```html\n\u003cbutton *on[click].once=\"count++\" type=\"button\"\u003eIncrement\u003c/button\u003e\n```\n\n#### `prevent`\n\nPrevent the default behavior of the event.\n\n```html\n\u003cform *on[submit].prevent=\"alert('Form submitted!')\"\u003e\n    \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n\u003c/form\u003e\n```\n\n#### `stop`\n\nStop the propagation of the event.\n\n```html\n\u003cdiv *on[click]=\"alert('Div clicked!')\"\u003e\n    \u003cbutton *on[click].stop=\"alert('Button clicked!')\" type=\"button\"\u003eClick Me\u003c/button\u003e\n\u003c/div\u003e\n```\n\n#### `window`\n\nListen for the event on the window object.\n\n```html\n\u003cinput type=\"search\" *on[keydown].esc.window=\"console.log('Escape key pressed!')\"/\u003e\n```\n\n#### `document`\n\nListen for the event on the document object.\n\n```html\n\u003cinput type=\"search\" *on[keydown].esc.document=\"console.log('Escape key pressed!')\"/\u003e\n```\n\n#### `self`\n\nListen for the event only if the event was dispatched from the element itself.\n\n```html\n\u003cbutton type=\"button\" *on[click].self=\"alert('Div clicked!')\"\u003e\n    Click Me\n    \n    \u003cimg src=\"https://placekitten.com/200/300\" alt=\"Kitten\" /\u003e\n\u003c/button\u003e\n```\n\nWith the `self` modifier, the alert will only be triggered if the button itself is clicked and not the image inside the button.\n\n#### `debounce`/`throttle`\n\nDebounce or throttle the event listener.\n\n```html\n\u003cinput type=\"search\" *on[input].debounce[500ms]=\"console.log($event.target.value)\"/\u003e\n\n\u003cinput type=\"search\" *on[input].throttle[500ms]=\"console.log($event.target.value)\"/\u003e\n```\n\nThe `debounce` modifier will wait for the specified time before executing the expression while the `throttle` modifier will execute the expression at most once every specified time.\n\nFor the duration, the time can be specified in milliseconds `ms` or seconds `s` or minutes `m` e.g. `500ms`, `1s`, `2m`, etc.\n\n#### `passive`\n\nYou can add `.passive` to your listeners to not block scroll performance when on touch devices.\n\n```html\n\u003cdiv *on[scroll].passive=\"console.log('Scrolling...')\"\u003e\n    ...\n\u003c/div\u003e\n```\n\n#### `capture`\n\nExecute the event listener during the capture phase of the event.\n\n```html\n\u003cdiv *on[click].capture=\"console.log('Capturing...')\"\u003e\n    ...\n\u003c/div\u003e\n```\n\n#### `away`\n\nListen for the event if it was dispatched outside the element.\n\n```html\n\u003cdiv *state=\"{ open: false }\" *on[click].away=\"open = false\"\u003e\n    \u003cbutton *on[click]=\"open = ! open\" type=\"button\"\u003eToggle\u003c/button\u003e\n    \u003cdiv *show=\"open\"\u003eThis is a dropdown\u003c/div\u003e\n\u003c/div\u003e\n```\n\n#### Keyboard Modifiers\n\nYou can also use the following keyboard modifiers to tweak your keyboard event listeners:\n\n- `.esc` - Escape key\n- `.enter` - Enter key\n- `.space` - Space key\n- `.tab` - Tab key\n- `.meta` - Meta/Command/Windows/Super key (aliased to `cmd`, `super`)\n- `.ctrl` - Control key\n- `.alt` - Alt key\n- `.shift` - Shift key\n- `.backspace` - Backspace key\n- `.delete` - Delete key\n- `.caps` - Caps Lock key\n- `.slash` - Slash key\n- `.period` - Period/Dot/Full Stop key\n- `.equal` - Equal/Plus key\n- `.comma` - Comma key\n- `.up` - Up arrow key\n- `.down` - Down arrow key\n- `.left` - Left arrow key\n- `.right` - Right arrow key\n\n### `text`\n\nSets the text content of an element.\n\n```html\n\u003ch1 *text=\"count\"\u003e\u003c/h1\u003e\n```\n\n### `html`\n\nSets the inner HTML of an element (Only use on trusted content and never on user-provided content. ⚠️ Dynamically rendering HTML from third parties can easily lead to XSS vulnerabilities.).\n\n```html\n\u003cdiv *html=\"post.content\"\u003e\u003c/div\u003e\n```\n\n### `show`\n\nToggle the visibility of an element based on the truthiness of an expression.\n\n```html\n\u003cdiv *state=\"{ open: false }\"\u003e\n    \u003cdiv *show=\"open\"\u003eThis is a hidden content\u003c/div\u003e\n    \u003cbutton *on[click]=\"open = !open\" type=\"button\"\u003eToggle\u003c/button\u003e\n\u003c/div\u003e\n```\n\n### `ref`\n\nReference elements directly by their specified keys using the `$refs` magic property.\n\n```html\n\u003cbutton data-text=\"Copy Me\" *ref=\"copyButton\" *on[click]=\"navigator.clipboard.writeText($refs.copyButton.dataset.text)\"\u003e\n    Copy\n\u003c/button\u003e\n```\n\n### `if`\n\nConditionally render an element based on the truthiness of an expression.\n\n```html\n\u003cdiv *state=\"{ loggedIn: false }\"\u003e\n    \u003ctemplate *if=\"loggedIn\"\u003e\n        \u003cdiv\u003eWelcome back!\u003c/div\u003e\n    \u003c/template\u003e\n    \u003ctemplate *if=\"! loggedIn\"\u003e\n        \u003cdiv\u003ePlease login to continue\u003c/div\u003e\n    \u003c/template\u003e\n    \u003cbutton *on[click]=\"loggedIn = !loggedIn\" type=\"button\" *text=\"loggedIn ? 'Logout' : 'Login'\"\u003e\u003c/button\u003e\n\u003c/div\u003e\n```\n\nNOTE: `*if` MUST be declared on a `\u003ctemplate\u003e` element and that `\u003ctemplate\u003e` element MUST contain only one root element.\n\n### `for`\n\nLoop over an array or object and render a template for each item.\n\n```html\n\u003ctemplate *for=\"post in posts\"\u003e\n  \u003ch2 *text=\"post.title\"\u003e\u003c/h2\u003e\n\u003c/template\u003e\n```\n\nYou can also get the index/object key of the current item by using the following syntax:\n\n```html\n\u003ctemplate *for=\"(post, index) in posts\"\u003e\n  \u003ch2 *text=\"index + 1 + '. ' + post.title\"\u003e\u003c/h2\u003e\n\u003c/template\u003e\n```\n\nBut keep it in mind that when dealing with objects, you probably want to use bracket access syntax to enable reactivity because JavaScript loses access to object internal state when destructuring:\n\n```html\n\u003ctemplate *for=\"(_, key) in user\"\u003e\n    \u003cli *text=\"`${key.toUpperCase()}: ${user[key]}`\"\u003e\u003c/li\u003e\n\u003c/template\u003e\n```\n\nIt is also important to specify a unique key for each item in the list to help the library keep track of the items and update the DOM efficiently. You can do this by adding a colon `:` after the `in` keyword followed by the key expression.\n\n```html\n\u003ctemplate *for=\"post in posts : post.id\"\u003e\n  \u003ch2 *text=\"post.title\"\u003e\u003c/h2\u003e\n\u003c/template\u003e\n```\n\nNOTE: `*for` MUST be declared on a `\u003ctemplate\u003e` element and that `\u003ctemplate\u003e` element MUST contain only one root element.\n\n### `model`\n\nTwo-way data binding for form elements.\n\n```html\n\u003cinput *model=\"name\" type=\"text\" /\u003e\n\u003cp *text=\"name\"\u003e\u003c/p\u003e\n```\n\n### `ignore`\n\nInstruct the library to skip processing a node and all of its children.\n\n```html\n\u003cinput *ignore type=\"datetime-local\" onload=\"new Pikaday(this)\" /\u003e\n```\n\nYou can use the `self` modifier to skip the element but process its children.\n\n### `cloak`\n\nYou can use this directive in conjunction with CSS to hide an element until it is ready to be processed to prevent UI flashes.\n\n```html\n\u003cstyle\u003e\n    [\\*cloak] {\n        display: none !important;\n    }\n\u003c/style\u003e\n\n\u003cdiv *state=\"{ open: false }\"\u003e\n    \u003cdiv *cloak *show=\"open\"\u003eThis is a hidden content\u003c/div\u003e\n    \u003cbutton *on[click]=\"open = !open\" type=\"button\"\u003eToggle\u003c/button\u003e\n\u003c/div\u003e\n```\n\n### `confirm`\n\nPrompt the user with a confirmation dialog before executing the attached event listeners.\n\n```html\n\u003cdiv *state=\"{authed: false}\"\u003e\n    \u003ctemplate *if=\"!authed\"\u003e\n        \u003cdiv\u003e\n            \u003cp\u003eYou are not logged in!\u003c/p\u003e\n\n            \u003cbutton *on[click]=\"authed = true\" type=\"button\"\u003eLogin\u003c/button\u003e\n        \u003c/div\u003e\n    \u003c/template\u003e\n\n    \u003ctemplate *if=\"authed\"\u003e\n        \u003cdiv\u003e\n            \u003cp\u003eWelcome back!\u003c/p\u003e\n\n            \u003cbutton *on[click]=\"authed = false\" *confirm=\"Are you sure you want to logout?\" type=\"button\"\u003eLogout\u003c/button\u003e\n\n            \u003cbutton *on[click]=\"authed = false\" *confirm.prompt=\"Type 'DELETE' to remove your account|DELETE\" type=\"button\"\u003eDelete Account\u003c/button\u003e\n        \u003c/div\u003e\n    \u003c/template\u003e\n\u003c/div\u003e\n```\n\nYou can use the `.prompt` modifier to prompt the user to enter a specific value, you need to separate the message and the expected value with a pipe `|`.\n\n## Magics\n\nMagics are special properties that are available in the state object and can be used in expressions.\n\nThey are prefixed with the `$` character to prevent conflicts with your normal state properties.\n\n### `$root`\n\nThe `$root` magic property gives you access to the element where the state object was declared.\n\n```html\n\u003cdiv *state=\"{}\" data-message=\"Hello World!\"\u003e\n    \u003cbutton type=\"button\" *on[click]=\"alert($root.dataset.message)\"\u003e\n        Greet Me\n    \u003c/button\u003e\n\u003c/div\u003e\n```\n\n### `$el`\n\nThe `$el` magic property gives you access to the current element.\n\n```html\n\u003cbutton *on[click]=\"$el.innerHTML = 'Hello World!'\"\u003eReplace me with \"Hello World!\"\u003c/button\u003e\n```\n\n### `$refs`\n\nThe `$refs` magic property gives you access to the elements with the `ref` directive.\n\n```html\n\u003cbutton data-text=\"Copy Me\" *ref=\"copyButton\" *on[click]=\"navigator.clipboard.writeText($refs.copyButton.dataset.text)\"\u003e\n    Copy\n\u003c/button\u003e\n```\n\n### `$parent`\n\nThe `$parent` magic property gives you access to the parent state object.\n\n```html\n\u003cdiv *state=\"{ count: 0 }\"\u003e\n    \u003ch1 *text=\"count\"\u003e\u003c/h1\u003e\n    \u003cbutton *state=\"{ text: 'Increment' }\" *on[click]=\"$parent.count++\" *text=\"text\"\u003e\u003c/button\u003e\n\u003c/div\u003e\n```\n\n### `$get`\n\nThe `$get` magic property allows you to access the value of a state property using dot-syntax.\n\n```html\n\u003cdiv *state=\"{ user: { name: 'John Doe' } }\"\u003e\n    \u003cp *text=\"$get('user.name')\"\u003e\u003c/p\u003e\n\u003c/div\u003e\n```\n\n### `$set`\n\nThe `$set` magic property allows you to update the value of a state property using dot-syntax.\n\n```html\n\u003cdiv *state=\"{ user: { name: 'John Doe' } }\"\u003e\n    \u003cinput *model=\"name\" type=\"text\" /\u003e\n    \u003cbutton *on[click]=\"$set('user.name', 'Jane Doe')\" type=\"button\"\u003eUpdate Name\u003c/button\u003e\n\u003c/div\u003e\n```\n\n### `$watch`\n\nThe `$watch` magic property allows you to watch for changes on a state property.\n\n```html\n\u003cdiv\n    *state=\"{\n        count: 0,\n        init() {\n            this.$watch('count', (value, oldValue) =\u003e {\n                console.log(`Count changed from ${oldValue} to ${value}`);\n            });\n        },\n    }\"\n\u003e\n    \u003cbutton type=\"button\" *on[click]=\"count++\"\u003e\n        Trigger Watch\n    \u003c/button\u003e\n\u003c/div\u003e\n```\n\n### `$effect`\n\nThe `$effect` magic property will run a function on mount and whenever one of the state properties used in it changes.\n\n```html\n\u003cdiv\n    *state=\"{\n        count: 0,\n        double: 0,\n        init() {\n            this.$effect(() =\u003e {\n                this.double = this.count * 2;\n            });\n        },\n    }\"\n\u003e\n    \u003ch1 *text=\"double\"\u003e\u003c/h1\u003e\n    \u003cbutton type=\"button\" *on[click]=\"count++\"\u003e\n        Double Increment\n    \u003c/button\u003e\n\u003c/div\u003e\n```\n\n### `$data`\n\nThe `$data` magic property gives you access to the state object, useful for when you want to send the whole thing to an API.\n\n```html\n\u003cdiv *state=\"{ count: 0 }\"\u003e\n    \u003cbutton type=\"button\" *on[click]=\"fetch('https://httpbin.org/post', { method: 'POST', body: JSON.stringify($data) })\"\u003e\n        Increment\n    \u003c/button\u003e\n\u003c/div\u003e\n```\n\n## Credits\n\n- [Hammed Oyedele](https://github.com/devhammed) - Author\n- [AlpineJS](https://alpinejs.dev/) - Inspiration\n- [VueJS](https://vuejs.org/) - Inspiration\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevhammed%2Fwickedstate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevhammed%2Fwickedstate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevhammed%2Fwickedstate/lists"}