{"id":50665017,"url":"https://github.com/dmke/actionview-vue_tag_helper","last_synced_at":"2026-06-08T05:32:21.231Z","repository":{"id":360280526,"uuid":"1249456215","full_name":"dmke/actionview-vue_tag_helper","owner":"dmke","description":"Vue Islands helper for ActionView","archived":false,"fork":false,"pushed_at":"2026-05-25T18:20:29.000Z","size":22,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-25T20:19:25.808Z","etag":null,"topics":["actionview","islands-architecture","rubygem","vue"],"latest_commit_sha":null,"homepage":"","language":"Ruby","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/dmke.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","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":"2026-05-25T18:09:04.000Z","updated_at":"2026-05-25T18:20:32.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dmke/actionview-vue_tag_helper","commit_stats":null,"previous_names":["dmke/actionview-vue_tag_helper"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/dmke/actionview-vue_tag_helper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmke%2Factionview-vue_tag_helper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmke%2Factionview-vue_tag_helper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmke%2Factionview-vue_tag_helper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmke%2Factionview-vue_tag_helper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dmke","download_url":"https://codeload.github.com/dmke/actionview-vue_tag_helper/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmke%2Factionview-vue_tag_helper/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34050224,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"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":["actionview","islands-architecture","rubygem","vue"],"created_at":"2026-06-08T05:32:21.161Z","updated_at":"2026-06-08T05:32:21.221Z","avatar_url":"https://github.com/dmke.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# actionview-vue_tag_helper\n\nAn ActionView helper for embedding Vue components in server-rendered HTML,\ntargeting the [Islands architecture](https://jasonformat.com/islands-architecture/):\nmultiple independent Vue instances mounted on otherwise static pages,\nwithout a full SPA or SSR pipeline.\n\n## Overview\n\nIn the Islands model, Rails delivers ordinary HTML and Vue is mounted on\nindividual \"islands\" — interactive widgets that need typed props, reactive\nstate, or component-library primitives. The built-in `tag` helper works\nfine for plain HTML but is a poor fit here: it always uses double-quote\ndelimiters and entity-encodes `\"` inside attribute values, turning a\nsimple JSON prop into noise, and it has no concept of Vue's typed props\nor `v-bind` shorthand.\n\n`actionview-vue_tag_helper` provides a `vue` helper with the same\nbuilder interface but tuned for Vue component output:\n\n```erb\n\u003c%# tag helper — double-quotes force \u0026quot; encoding inside JSON %\u003e\n\u003c%= tag.my_component data: { config: {key: \"val\"}.to_json } %\u003e\n\u003c%# =\u003e \u003cmy-component data-config=\"{\u0026quot;key\u0026quot;:\u0026quot;val\u0026quot;}\"\u003e\u003c/my-component\u003e %\u003e\n\n\u003c%# vue helper — switches to single quotes when the value contains \" %\u003e\n\u003c%= vue.my_component data: { config: {key: \"val\"} } %\u003e\n\u003c%# =\u003e \u003cmy-component data-config='{\"key\":\"val\"}'\u003e\u003c/my-component\u003e %\u003e\n```\n\n### Tag names\n\nMethod names are dasherized: `vue.my_feed_item` and `vue.MyFeedItem`\nboth produce `\u003cmy-feed-item\u003e`. The resulting name must contain at least\none hyphen (the HTML Living Standard requirement for custom element\nnames). Anything that doesn't meet this — a plain word like `vue.div`,\nfor example — raises `ArgumentError` immediately.\n\nEvery tag is emitted with an explicit closing tag; Vue component tags are\nnever self-closing.\n\n### Typed attributes / v-bind shorthand\n\nVue components use typed props. Passing `count=\"42\"` (a string) when the\ncomponent declares `count: Number` triggers a Vue runtime warning. The\n`vue` helper avoids this by inspecting the Ruby value:\n\n| Ruby value | Emitted attribute |\n|:-----------|:------------------|\n| `String`, `Symbol` | `label=\"hello\"` — plain attribute |\n| `true`             | `disabled` — valueless (Vue treats presence as truthy) |\n| `Integer`, `Float`, `false`, `Array`, `Hash`, … | `:count=\"42\"` — v-bind shorthand, value serialised as JSON |\n\n```erb\n\u003c%= vue.b_btn(disabled: true) %\u003e\n\u003c%# =\u003e \u003cb-btn disabled\u003e\u003c/b-btn\u003e %\u003e\n\n\u003c%= vue.x_counter(count: 42, ratio: 1.5) %\u003e\n\u003c%# =\u003e \u003cx-counter :count=\"42\" :ratio=\"1.5\"\u003e\u003c/x-counter\u003e %\u003e\n\n\u003c%= vue.my_component(items: %w[a b]) %\u003e\n\u003c%# =\u003e \u003cmy-component :items='[\"a\",\"b\"]'\u003e\u003c/my-component\u003e %\u003e\n```\n\nThe `class:` key is exempt: an `Array` or `Hash` value is always\nflattened into a space-separated CSS token list, never v-bound.\n\n### `data:` and `aria:` hashes\n\nA Hash under `data:` or `aria:` is expanded into individual prefixed\nattributes. Complex values are serialised to JSON; `aria:` values are\nalways plain strings (WAI-ARIA is string-based).\n\n```erb\n\u003c%= vue.my_component(data: { user: { id: 1, name: \"Alice\" } }) %\u003e\n\u003c%# =\u003e \u003cmy-component data-user='{\"id\":1,\"name\":\"Alice\"}'\u003e\u003c/my-component\u003e %\u003e\n```\n\n## Installation\n\nAdd to your `Gemfile`:\n\n```ruby\ngem \"actionview-vue_tag_helper\"\n```\n\nThe helper is available in all views as soon as the gem is loaded. No\n`include` or initialiser is required — it hooks into ActionView via\n`ActiveSupport.on_load(:action_view)`.\n\n## Contributing\n\nPull requests are welcome. Please always add a test with your changes.\n\n### Prerequisites\n\n- [rbenv](https://github.com/rbenv/rbenv) with the\n  [rbenv-gemset](https://github.com/jf/rbenv-gemset) plugin\n- Ruby 4.0 (`rbenv install 4.0`)\n\nThe project uses local gemsets stored under `.gems/` (gitignored).\n`.ruby-version` and `.ruby-gemset` are already checked in, so rbenv\npicks up the right Ruby and gemset automatically when you `cd` into the\nproject.\n\n### Setup\n\n```sh\ngit clone https://github.com/dmke/actionview-vue_tag_helper\ncd actionview-vue_tag_helper\nbundle install   # installs into .gems/4.0/...\n```\n\n### Running the tests\n\nAgainst the default gemfile (Rails 8.1):\n\n```sh\nbundle exec rspec\n```\n\nAgainst all supported Rails versions:\n\n```sh\nbin/test\n```\n\nEach gemfile gets its own isolated gemset under `.gems/` (e.g.\n`.gems/rails_8_0`, `.gems/rails_8_1`, `.gems/rails_main`).\n\n### Updating dependencies\n\n```sh\nbin/bundle-all update\n```\n\n### Cleaning stale gems\n\n```sh\nbin/bundle-all clean --force\n```\n\n### Linting\n\n```sh\nbundle exec rubocop\n```\n\n## License\n\nMIT - see [LICENSE.txt](LICENSE.txt).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmke%2Factionview-vue_tag_helper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdmke%2Factionview-vue_tag_helper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmke%2Factionview-vue_tag_helper/lists"}