{"action":"created","issue":{"url":"https://api.github.com/repos/sveltejs/svelte/issues/875","repository_url":"https://api.github.com/repos/sveltejs/svelte","labels_url":"https://api.github.com/repos/sveltejs/svelte/issues/875/labels{/name}","comments_url":"https://api.github.com/repos/sveltejs/svelte/issues/875/comments","events_url":"https://api.github.com/repos/sveltejs/svelte/issues/875/events","html_url":"https://github.com/sveltejs/svelte/issues/875","id":261127506,"node_id":"MDU6SXNzdWUyNjExMjc1MDY=","number":875,"title":"Passing data to custom elements","user":{"login":"Rich-Harris","id":1162160,"node_id":"MDQ6VXNlcjExNjIxNjA=","avatar_url":"https://avatars3.githubusercontent.com/u/1162160?v=4","gravatar_id":"","url":"https://api.github.com/users/Rich-Harris","html_url":"https://github.com/Rich-Harris","followers_url":"https://api.github.com/users/Rich-Harris/followers","following_url":"https://api.github.com/users/Rich-Harris/following{/other_user}","gists_url":"https://api.github.com/users/Rich-Harris/gists{/gist_id}","starred_url":"https://api.github.com/users/Rich-Harris/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Rich-Harris/subscriptions","organizations_url":"https://api.github.com/users/Rich-Harris/orgs","repos_url":"https://api.github.com/users/Rich-Harris/repos","events_url":"https://api.github.com/users/Rich-Harris/events{/privacy}","received_events_url":"https://api.github.com/users/Rich-Harris/received_events","type":"User","site_admin":false},"labels":[{"id":485407406,"node_id":"MDU6TGFiZWw0ODU0MDc0MDY=","url":"https://api.github.com/repos/sveltejs/svelte/labels/enhancement","name":"enhancement","color":"84b6eb","default":true},{"id":498304764,"node_id":"MDU6TGFiZWw0OTgzMDQ3NjQ=","url":"https://api.github.com/repos/sveltejs/svelte/labels/pending%20clarification","name":"pending clarification","color":"d4c5f9","default":false},{"id":795423890,"node_id":"MDU6TGFiZWw3OTU0MjM4OTA=","url":"https://api.github.com/repos/sveltejs/svelte/labels/proposal","name":"proposal","color":"1d76db","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":11,"created_at":"2017-09-27T21:42:57Z","updated_at":"2018-08-06T00:09:31Z","closed_at":null,"author_association":"MEMBER","body":"When passing data to a custom element, there are two possibilities — properties, or attributes.\r\n\r\nRight now, Svelte doesn't have any understanding of custom elements, so on encountering something [like this](https://svelte.technology/repl?version=1.40.1&gist=727e7d30398b9c16f7942a4a14287d50)...\r\n\r\n```html\r\n<custom-element foo='bar'></custom-element>\r\n```\r\n\r\n...it will [look here](https://github.com/sveltejs/svelte/blob/master/src/generators/dom/visitors/Element/lookup.ts), fail to find a property corresponding to the `foo` attribute, and fall back to writing this:\r\n\r\n```js\r\nsetAttribute(custom_element, \"foo\", \"bar\");\r\n```\r\n\r\nThat's sub-optimal, because it means we can't pass down non-string values — especially not objects and arrays. For those, we need to use props.\r\n\r\nAt the same time, *always* using props could be a problem for custom elements that expect attributes to change. It's also a problem if a custom element has CSS like this, say...\r\n\r\n```css\r\n:host([active]) {\r\n  font-weight: bold;\r\n}\r\n```\r\n\r\n...because then if you have a situation like this...\r\n\r\n```html\r\n<custom-element active='{{thing === selected}}'></custom-element>\r\n```\r\n\r\n...the prop will be maintained correctly but the attribute won't ever change, meaning the styles will never apply.\r\n\r\n## A possible solution\r\n\r\nDo both. Or rather, *always* set a prop, but also set an attribute if the value is primitive.\r\n\r\nSo the example at the top would become this:\r\n\r\n```js\r\ncustom_element.foo = \"bar\";\r\nsetAttribute(custom_element, \"foo\", \"bar\");\r\n```\r\n\r\nFor dynamic values, it would be more like this:\r\n\r\n```js\r\ncustom_element.foo = state.bar;\r\n\r\nif (typeof state.bar === \"boolean\" || typeof state.bar === \"undefined\") {\r\n  if (state.bar) {\r\n    setAttribute(custom_element, \"foo\", \"\");\r\n  } else {\r\n    removeAttribute(custom_element, \"foo\");\r\n  }\r\n} elseif (typeof state.bar === \"string\" || typeof state.bar === \"number\") {\r\n  setAttribute(custom_element, \"foo\", state.bar);\r\n}\r\n```\r\n\r\nNeedless to say, all that logic would live in a helper.\r\n\r\n## kebab-case vs camelCase\r\n\r\nSince props *can't* be kebab-case, I propose that we translate kebab to camel when setting props:\r\n\r\n```html\r\n<custom-element the-answer='{{fortyTwo}}'></custom-element>\r\n```\r\n\r\n```js\r\ncustom_element.theAnswer = state.fortyTwo;\r\nsetCustomElementAttribute(custom_element, \"the-answer\", state.fortyTwo);\r\n```\r\n\r\n---\r\n\r\nThis might seem slightly messy, but I think it's the most pragmatic way to deal with this stuff, and the way that will result in the least surprising behaviour for the largest number of people. No-one ever said custom elements were particularly well designed. (Actually, lots of people did, but most of them work for Google.)\r\n\r\nThoughts?"},"comment":{"url":"https://api.github.com/repos/sveltejs/svelte/issues/comments/410558472","html_url":"https://github.com/sveltejs/svelte/issues/875#issuecomment-410558472","issue_url":"https://api.github.com/repos/sveltejs/svelte/issues/875","id":410558472,"node_id":"MDEyOklzc3VlQ29tbWVudDQxMDU1ODQ3Mg==","user":{"login":"zigomir","id":957321,"node_id":"MDQ6VXNlcjk1NzMyMQ==","avatar_url":"https://avatars1.githubusercontent.com/u/957321?v=4","gravatar_id":"","url":"https://api.github.com/users/zigomir","html_url":"https://github.com/zigomir","followers_url":"https://api.github.com/users/zigomir/followers","following_url":"https://api.github.com/users/zigomir/following{/other_user}","gists_url":"https://api.github.com/users/zigomir/gists{/gist_id}","starred_url":"https://api.github.com/users/zigomir/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zigomir/subscriptions","organizations_url":"https://api.github.com/users/zigomir/orgs","repos_url":"https://api.github.com/users/zigomir/repos","events_url":"https://api.github.com/users/zigomir/events{/privacy}","received_events_url":"https://api.github.com/users/zigomir/received_events","type":"User","site_admin":false},"created_at":"2018-08-06T00:09:31Z","updated_at":"2018-08-06T00:09:31Z","author_association":"NONE","body":"👍 I see, thanks for the response!\r\n\r\nAnother question; is there a way to tell through svelte that custom property attribute is a number and not a string?\r\n\r\n```html\r\n<custom-element start=\"1\" />\r\n```\r\n\r\nSvelte will generate a getter as\r\n\r\n```js\r\nget start() {\r\n  return this.get().start;\r\n}\r\n```\r\n\r\nbut this will always return a string.\r\n\r\nI know I can do\r\n\r\n```js\r\nconst el = document.querySelector('custom-element')\r\nel.start = 1\r\n```\r\n\r\nbut that just doesn't look so good :)"}}
{"actor":{"display_login":"zigomir"}}