{"id":41150048,"url":"https://github.com/janosgyerik/upvotejs","last_synced_at":"2026-01-22T19:01:57.675Z","repository":{"id":9042605,"uuid":"10805910","full_name":"janosgyerik/upvotejs","owner":"janosgyerik","description":"UpvoteJS generates a voting widget like the one used on Stack Exchange sites","archived":false,"fork":false,"pushed_at":"2023-03-30T06:46:23.000Z","size":479,"stargazers_count":148,"open_issues_count":20,"forks_count":54,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-09-29T16:22:19.262Z","etag":null,"topics":["javascript","stackexchange","stackoverflow","voting","widget"],"latest_commit_sha":null,"homepage":"https://janosgyerik.github.io/upvotejs","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/janosgyerik.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2013-06-19T20:50:39.000Z","updated_at":"2024-11-30T17:09:18.000Z","dependencies_parsed_at":"2026-01-07T16:09:23.338Z","dependency_job_id":null,"html_url":"https://github.com/janosgyerik/upvotejs","commit_stats":null,"previous_names":["janosgyerik/jquery-upvote"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/janosgyerik/upvotejs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/janosgyerik%2Fupvotejs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/janosgyerik%2Fupvotejs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/janosgyerik%2Fupvotejs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/janosgyerik%2Fupvotejs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/janosgyerik","download_url":"https://codeload.github.com/janosgyerik/upvotejs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/janosgyerik%2Fupvotejs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28668834,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-22T17:07:18.858Z","status":"ssl_error","status_checked_at":"2026-01-22T17:05:02.040Z","response_time":144,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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":["javascript","stackexchange","stackoverflow","voting","widget"],"created_at":"2026-01-22T19:01:49.177Z","updated_at":"2026-01-22T19:01:57.647Z","avatar_url":"https://github.com/janosgyerik.png","language":"JavaScript","funding_links":["https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick\u0026hosted_button_id=SQTLZB5QCLR82"],"categories":[],"sub_categories":[],"readme":"UpvoteJS\n========\n\n[![Build Status](https://travis-ci.org/janosgyerik/upvotejs.svg?branch=master)](https://travis-ci.org/janosgyerik/upvotejs)\n\n`UpvoteJS` is a JavaScript package to create a voting widget that looks like\nthe one used on [Stack][stackoverflow] [Exchange][superuser] [sites][serverfault].\nFor example, like this:\n\n![Screenshot featuring stackoverflow.com, superuser.com, serverfault.com][feature]\n\nUsing the package\n-----------------\n\nThere are different ways to use the package, depending on your use case.\n\n### Create a \"read-only\" widget in HTML\n\nThat is, have a nicely rendered widget based on HTML markup alone,\nto simply represent some state, that cannot be modified by user action.\nIn this mode, no JavaScript is needed, and the counter, the upvote/downvote arrows\nand the star are rendered based on the HTML markup alone.\n\nInclude the stylesheet in your page's `\u003chead\u003e` element, for example:\n\n    \u003clink rel=\"stylesheet\" href=\"dist/upvotejs/upvotejs.css\"\u003e\n\nMake sure the image `upvotejs.svg` is present in the same directory as the `upvotejs.css` file.\n\nInclude this basic HTML boilerplate for each vote:\n\n    \u003cdiv id=\"the-id\" class=\"upvotejs\"\u003e\n        \u003ca class=\"upvote\"\u003e\u003c/a\u003e\n        \u003cspan class=\"count\"\u003e0\u003c/span\u003e\n        \u003ca class=\"downvote\"\u003e\u003c/a\u003e\n        \u003ca class=\"star\"\u003e\u003c/a\u003e\n    \u003c/div\u003e\n\nCustomize the boilerplate with values appropriate for the vote you want to display:\n\n- Set the correct value for `.count`\n- For upvoted state, add class `upvote-on` for `.upvote`\n- For downvoted state, add class `downvote-on` for `.downvote`\n- For starred state, add class `star-on` for `.star`\n\nWith only HTML code, the widget is read-only, the voting and star buttons are not clickable.\n\n### Create an interactive widget\n\nThat is, enable user interactions to upvote, downvote, or star,\nmodifying the state of the counter.\nHowever, storing the state on some backend is still out of scope in this mode.\n\nInclude the JavaScript sources in your page's `\u003chead\u003e` element, for example:\n\n    \u003cscript src=\"dist/upvotejs/upvotejs.vanilla.js\"\u003e\u003c/script\u003e\n\nCreate the Upvote widget controller:\n\n    Upvote.create('id');\n\nWhere `id` is the ID of the widget in the DOM.\n\nWith this step, the controls of the widget will become clickable, upvoting and downvoting will update the count and indicate toggled state, so will the star, and consistent state will be enforced.\n\nWith HTML and JavaScript code alone, the state of the widget will not be persisted in any storage.\n\n### Save the state of the widget to some backend\n\nIn order to save the state of the widget in response to user action,\npass a callback handler when creating the widget, for example:\n\n    Upvote.create('id', {callback: your_callback_handler});\n\nOn any change to the state of the widget (vote up, vote down, or star),\nthe callback handler will be called, with a JSON object as parameter,\nwith fields:\n\n- `id`: the id of the DOM object, the same value that was used when creating with `Upvote.create`\n\n- `action`: the user action that triggered the state change.\n  Possible values: `upvote`, `unupvote`, `downvote`, `undownvote`, `star`, `unstar`\n\n- `newState`: a JSON object with fields:\n  - `count`: the current vote count\n  - `upvoted`: `true` if the widget is in upvoted state\n  - `downvoted`: `true` if the widget is in downvoted state\n  - `starred`: `true` if the widget is in starred state\n\nNote that `upvoted` and `downvoted` will never be `true` at the same time.\n\nAn example payload:\n\n    {\n      id: 'my-vote',\n      action: 'upvote',\n      newState: {\n        count: 123,\n        upvoted: true,\n        downvoted: false,\n        starred: true\n      }\n    }\n\nUsing this data object, it is up to your implementation of `your_callback_handler` to actually implement writing the new state on some backend, for example with a `POST` or `PATCH` call to a storage service to update the user's vote.\n\n### Using with jQuery\n\nIt's possible to use the package through jQuery, if you prefer (though not clear why).\n\nInclude the following in `\u003chead\u003e`:\n\n    \u003clink rel=\"stylesheet\" href=\"dist/upvotejs/upvotejs.css\"\u003e\n    \u003cscript src=\"dist/upvotejs/upvotejs.vanilla.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"dist/upvotejs/upvotejs.jquery.js\"\u003e\u003c/script\u003e\n\nMake sure the image `upvotejs.svg` is present in the same directory as the `upvotejs.css` file.\n\nInitialization examples:\n\n    $('#topic').upvote();\n    $('#topic').upvote({count: 5, upvoted: true});\n    $('#topic').upvote({count: 5, downvoted: true});\n    $('#topic').upvote({count: 5, upvoted: true, starred: true});\n\n    var callback = function(data) {\n        $.ajax({\n            url: '/vote',\n            type: 'post',\n            data: data\n        });\n    };\n    $('#topic-123').upvote({id: 123, callback: callback});\n\nMethods:\n\n    // Create, pick up initial values from HTML markup\n    $('#topic').upvote();\n\n    // Mutators\n    $('#topic').upvote('upvote');       // Upvote!\n    $('#topic').upvote('downvote');     // Downvote!\n    $('#topic').upvote('star');         // Star!\n\n    // Getters\n    $('#topic').upvote('count');        // Get the current vote count\n    $('#topic').upvote('upvoted');      // Get the upvoted state -\u003e boolean\n    $('#topic').upvote('downvoted');    // Get the downvoted state -\u003e boolean\n    $('#topic').upvote('starred');      // Get the starred state -\u003e boolean\n\nAPI reference\n-------------\n\nFiles:\n\n- `upvotejs.css` and `upvotejs.svg` are required for styling, and both must be in the same directory\n- `upvotejs.vanilla.js` is required for interactive use\n\nCreate an Upvote widget controller using `Upvote.create`:\n\n    const widget = Upvote.create(id, params = {});\n\nAn element in the DOM must exist with the specified `id`, and have a basic markup like this:\n\n    \u003cdiv id=\"the-id\" class=\"upvotejs\"\u003e\n        \u003ca class=\"upvote\"\u003e\u003c/a\u003e\n        \u003cspan class=\"count\"\u003e0\u003c/span\u003e\n        \u003ca class=\"downvote\"\u003e\u003c/a\u003e\n        \u003ca class=\"star\"\u003e\u003c/a\u003e\n    \u003c/div\u003e\n\nThe widget will be parameterized based on the markup of the DOM element:\n\n- The count is read from the value of `.count`\n- The state is considered upvoted if `.upvote` has `upvote-on` class.\n- The state is considered downvoted if `.downvote` has `downvote-on` class.\n- The state is considered starred if `.star` has `star-on` class.\n\nAn exception will be thrown in case of invalid DOM markup:\n\n- If a DOM element with the specified `id` doesn't exist\n- If the DOM element with `id` is already used by another Upvote widget controller\n- If the DOM element doesn't have all required components\n- If both upvoted and downvoted state are detected at the same time\n\nThe state values can be overridden explicitly using the `param` object, with fields:\n\n- `count` - the vote count to set, must be an integer\n- `upvoted` - a boolean to set upvoted state\n- `downvoted` - a boolean to set downvoted state\n- `starred` - a boolean to set starred state\n- `callback` - a function that will be called on any state change\n\nAn exception will be thrown in case of invalid parameters:\n\n- If the parameter types don't match expected values\n- If `upvoted` and `downvoted` are both `true`\n\n### Properties\n\nAn instance of an Upvote widget controller has the following properties:\n\n- `id`: the `id` of the controller\n- `count()`: get the current count\n- `upvote()`: toggle upvoted state\n- `upvoted()`: get the upvoted state\n- `downvote()`: toggle downvoted state\n- `downvoted()`: get the downvoted state\n- `star()`: toggle starred state\n- `starred()`: get the starred state\n\n### Event handling\n\nThe widget controller, on its creation, overwrites the `onclick` property of the selected DOM.\n\nOn `destroy`, the widget controller resets `onclick` to `null`.\n\nSponsors\n--------\n\nContributions from users and sponsors help make UpvoteJS possible.\nWe accept donations via [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick\u0026hosted_button_id=SQTLZB5QCLR82). Thanks! :)\n\nLicense\n-------\n\n\u003ca rel=\"license\" href=\"http://creativecommons.org/licenses/by/3.0/\"\u003e\u003cimg alt=\"Creative Commons License\" style=\"border-width:0\" src=\"https://i.creativecommons.org/l/by/3.0/88x31.png\" /\u003e\u003c/a\u003e\u003cbr /\u003eThis work is licensed under a \u003ca rel=\"license\" href=\"http://creativecommons.org/licenses/by/3.0/\"\u003eCreative Commons Attribution 3.0 Unported License\u003c/a\u003e.\n\n[stackoverflow]: http://stackoverflow.com/\n[superuser]: http://superuser.com/\n[serverfault]: http://serverfault.com/\n[feature]: images/feature.png\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjanosgyerik%2Fupvotejs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjanosgyerik%2Fupvotejs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjanosgyerik%2Fupvotejs/lists"}