{"id":"e93997d5089d7165","slug":"inputs","first_public_version":null,"paused_version":null,"likes":991,"publish_level":"public","forks":57,"fork_of":null,"has_importers":true,"thumbnail":"6f6e7093659df4dda57433ee288ccd798f86f669dfac0aa78b803205b34bc474","default_thumbnail":"d109ef39d520aee9715c22eb781a6964097bd4e272e781e56a61af8f25c70051","update_time":"2020-09-24T16:20:30.612Z","publish_time":"2018-01-24T19:37:53.774Z","publish_version":2303,"latest_version":2303,"roles":[],"sharing":null,"owner":{"id":"172cc08ef8a18a4b","avatar_url":"https://avatars.observableusercontent.com/avatar/fa1903f8171d4621ef49de28e0ff1fb965960ec87df175d8b543c4b09508b45b","login":"jashkenas","name":"Jeremy Ashkenas","bio":"Used to work on @observablehq — still think it rocks.\n🏍 🌎 👶","home_url":"http://ashkenas.com","type":"team","tier":"starter_2024"},"creator":{"id":"783616ba9fb55f5d","avatar_url":"https://avatars.observableusercontent.com/avatar/fa1903f8171d4621ef49de28e0ff1fb965960ec87df175d8b543c4b09508b45b","login":"jashkenas","name":"Jeremy Ashkenas","bio":"Used to work on @observablehq — still think it rocks.\n🏍 🌎 👶","home_url":"http://ashkenas.com","tier":"public"},"authors":[{"id":"783616ba9fb55f5d","avatar_url":"https://avatars.observableusercontent.com/avatar/fa1903f8171d4621ef49de28e0ff1fb965960ec87df175d8b543c4b09508b45b","name":"Jeremy Ashkenas","login":"jashkenas","bio":"Used to work on @observablehq — still think it rocks.\n🏍 🌎 👶","home_url":"http://ashkenas.com","tier":"public","approved":true,"description":""}],"files":[{"id":"c051fbc024553912e31968b35e537d4ad3592201b5f8e7bd13fd9d02e38599c5d541a704d0858c676328babb3e5c9c35dd7c6d67240090d094882a1cad8eece4","url":"https://static.observableusercontent.com/files/c051fbc024553912e31968b35e537d4ad3592201b5f8e7bd13fd9d02e38599c5d541a704d0858c676328babb3e5c9c35dd7c6d67240090d094882a1cad8eece4","download_url":"https://static.observableusercontent.com/files/c051fbc024553912e31968b35e537d4ad3592201b5f8e7bd13fd9d02e38599c5d541a704d0858c676328babb3e5c9c35dd7c6d67240090d094882a1cad8eece4?response-content-disposition=attachment%3Bfilename*%3DUTF-8%27%27capstan.gif","name":"capstan.gif","create_time":"2019-10-30T19:24:04.295Z","mime_type":"image/gif","status":"public","size":90036,"content_encoding":null,"private_bucket_id":null}],"comments":[{"id":"c38a1dbd3792e266","content":"Is it possible to use tex for the title?","node_id":50,"create_time":"2021-04-05T21:25:35.453Z","update_time":null,"resolved":false,"user":{"id":"af07eb04f9b42831","avatar_url":"https://avatars.observableusercontent.com/avatar/a8f90690a63c2c8b077263631eba4b1f06e9e29364568ef437b879c869e9feb1","login":"syaleni","name":"Siavash Habibi","bio":"Structural engineer and programmer based in Toronto, ON.","home_url":"http://vectoranalysisgroup.com","tier":"public"}},{"id":"2e73f9ffedd4582e","content":"2100","node_id":714,"create_time":"2025-09-14T23:08:33.960Z","update_time":null,"resolved":false,"user":{"id":"1871ea9b3d11f73d","avatar_url":"https://avatars.observableusercontent.com/avatar/19f7ee5b3f0947997db47b8146ffb872ad048b899d7996435cb987c8e56d016b","login":"lord-rebtail","name":"Lord Rebtail","bio":"","home_url":"","tier":"public"}},{"id":"0afabcbcf0798690","content":"🐛:\nDoesn't update it's checkbox state when manipulated via `viewof` as per\nhttps://observablehq.com/@mbostock/views-are-mutable-values","node_id":871,"create_time":"2020-12-16T11:45:15.417Z","update_time":null,"resolved":false,"user":{"id":"7aa2b2f3f4c45532","avatar_url":"https://avatars.observableusercontent.com/avatar/5c84375e303cfe995944d31a295628df714f891ba8ae3db413da319a8f74e8f1","login":"somethingelseentirely","name":"","bio":"","home_url":"","tier":"public"}},{"id":"aa6ada35e3b395b6","content":"Its be cool if this could support composite values like:-\n{label: \"1080p\",  value: {width:1920, height:1080}","node_id":918,"create_time":"2020-09-27T15:34:09.666Z","update_time":null,"resolved":false,"user":{"id":"5215f6ec4a999d40","avatar_url":"https://avatars.observableusercontent.com/avatar/47327a8bc1966f2186dcb3ebf4b7ee6e4e7ab9a5c2a07405aff57200ea778f71","login":"tomlarkworthy","name":"Tom Larkworthy","bio":"Tech Lead at Taktile. ex Firebase, Google.\n🦋 larkworthy.bsky.social","home_url":"https://bsky.app/profile/larkworthy.bsky.social","tier":"pro"}},{"id":"c366958247fe963f","content":"I've implemented this in a fork (https://observablehq.com/d/e7dcffd44724cd76) that Jeremy and I are discussing merging, and also as a wrapper function (https://observablehq.com/@harrybiddle/inputs-with-complex-values)","node_id":918,"create_time":"2020-10-11T17:11:04.928Z","update_time":null,"resolved":false,"user":{"id":"914ea1886092acdd","avatar_url":"https://avatars.observableusercontent.com/avatar/cb2de2eafd016bd637f3f9ddfb40954d06828995d8fd2e21d31a29d494015b09","login":"harrybiddle","name":"Harry Biddle","bio":"","home_url":"","tier":"public"}},{"id":"63cdc9e7117d006e","content":"Looks like this is now supported by Observable's inputs :) (https://observablehq.com/@observablehq/inputs)","node_id":918,"create_time":"2021-02-07T13:50:04.722Z","update_time":null,"resolved":false,"user":{"id":"914ea1886092acdd","avatar_url":"https://avatars.observableusercontent.com/avatar/cb2de2eafd016bd637f3f9ddfb40954d06828995d8fd2e21d31a29d494015b09","login":"harrybiddle","name":"Harry Biddle","bio":"","home_url":"","tier":"public"}},{"id":"dcf1efb2fa5a47e9","content":"Is there a way to have a full-width slider?","node_id":1591,"create_time":"2020-09-28T13:07:40.623Z","update_time":null,"resolved":false,"user":{"id":"2e1df79eb11834a9","avatar_url":"https://avatars.observableusercontent.com/avatar/1817a622719b68c15fd89c864643a2513d5e715681d61186936e60b95a0bcc0e","login":"llb4ll","name":"bea","bio":"","home_url":"https://4idea.de/","tier":"public"}},{"id":"56901bf44551561b","content":"Would like a slider with a ‘click‘ or notch in the middle.","node_id":1591,"create_time":"2020-11-07T13:02:50.701Z","update_time":null,"resolved":false,"user":{"id":"3c5ecb707ecd20a7","avatar_url":"https://avatars.observableusercontent.com/avatar/40dc8e4f86d0cf89184b173b4d1d88336e5728c175479f33261ced3496adb3c2","login":"martien","name":"Martien van Steenbergen","bio":"Wise Fool.\nVisioneer.","home_url":"http://aardrock.com","tier":"pro"}},{"id":"e70bb946d23e7b65","content":"I also want full-width slider too.\nOr custom size slider. :)","node_id":1591,"create_time":"2020-11-12T23:00:03.280Z","update_time":null,"resolved":false,"user":{"id":"beff0d78af332174","avatar_url":"https://avatars.observableusercontent.com/avatar/354f96f6cf5c6b283c7f322910758aa4d90cef52388b572e18bb02276c82a7dc","login":"sent44","name":"sent44","bio":"I want to draw the profile image myself, yet my skill is still not enough.","home_url":"","tier":"public"}},{"id":"a564901fc383a315","content":"Option to specify alternatives to the \"Longitude\" and \"Latitude\" labels for coordinates (e.g., astronomers use \"Right Ascension\" and \"Declination\").","node_id":1684,"create_time":"2020-08-16T13:54:39.998Z","update_time":null,"resolved":true,"user":{"id":"b31e222c78b643d7","avatar_url":"https://avatars.observableusercontent.com/avatar/5b2c32ac920111620eb8369d40c1cd0353430f60391a4e246bc9822ab20f6f2f","login":"dkirkby","name":"David Kirkby","bio":"","home_url":"https://faculty.sites.uci.edu/dkirkby/","tier":"pro"}},{"id":"c83707ccb5824c8a","content":"How about a slider width configuration option?","node_id":1684,"create_time":"2020-09-24T03:23:21.041Z","update_time":null,"resolved":false,"user":{"id":"daddaf42a984273e","avatar_url":"https://avatars.observableusercontent.com/avatar/bbe60764c397ed9826fe59b2673a38a234cf200a3e740e2bf2a47d21c21f6792","login":"filonik","name":"Daniel Filonik","bio":"","home_url":"","tier":"public"}},{"id":"5247acd95642b5c5","content":"A selectable map would be incredible such as clickable countries that highlight the country.","node_id":1684,"create_time":"2020-11-26T17:07:34.298Z","update_time":null,"resolved":false,"user":{"id":"a9fa082a4a2afaee","avatar_url":"https://avatars.observableusercontent.com/avatar/9692acc3ebba92b1f767dd69ddcde566170ab3562d70bd86007fbb3d2c54ae47","login":"stnachts","name":"Stephen Nachtsheim","bio":"","home_url":"","tier":"public"}},{"id":"99c673a5798ed8e4","content":"maybe a slider with a way to map to date values (yyy-mm-dd)","node_id":1684,"create_time":"2020-12-27T06:50:13.759Z","update_time":null,"resolved":false,"user":{"id":"385beb2db41b5e0e","avatar_url":"https://avatars.observableusercontent.com/avatar/2f77fb920bb26001eda95fd5d2d68c6ef23649865e043f0047b7f8edb0a21436","login":"josephhailu","name":"","bio":"","home_url":"","tier":"public"}},{"id":"3b86f51a3f4b7fd6","content":"ability to override css?","node_id":1684,"create_time":"2021-01-10T10:02:47.425Z","update_time":null,"resolved":false,"user":{"id":"32869872eb6f2f82","avatar_url":"https://avatars.observableusercontent.com/avatar/a5081aaa56ae9990aa27642040dc61de3ce8cea67f6f778a5b864e41111ba7a3","login":"dhowe","name":"Daniel Howe","bio":"whole watermelon eating cat","home_url":"","tier":"public"}},{"id":"e89f7fdd72da6726","content":"I would like a selectable date/time range. That let me select a time range between 2 dates/times. and return the start and end date/times.","node_id":1684,"create_time":"2022-06-20T01:10:44.518Z","update_time":null,"resolved":false,"user":{"id":"63b42567a0a8bbc6","avatar_url":"https://avatars.observableusercontent.com/avatar/cbd7fc6cd785cb81eb19167305b691e111f222fbd3686cc820dee06c5ec1e9f6","login":"fatman00","name":"Rasmus E","bio":"","home_url":"","tier":"public"}},{"id":"19cd6f7fbd0107bb","content":"This is really cool.","node_id":2112,"create_time":"2022-10-03T10:57:51.818Z","update_time":null,"resolved":false,"user":{"id":"1125ba366576bacb","avatar_url":"https://avatars.observableusercontent.com/avatar/40e4321204a4470fbee5dcc275c513d1f8bc8dbd5732a4f01aad221d0426f271","login":"novotny1akub","name":"novotny1akub","bio":"","home_url":"","tier":"public"}},{"id":"6e65fdfdd52a36df","content":"Is it possible to select multiple options here?","node_id":2112,"create_time":"2022-10-03T11:00:09.762Z","update_time":null,"resolved":false,"user":{"id":"1125ba366576bacb","avatar_url":"https://avatars.observableusercontent.com/avatar/40e4321204a4470fbee5dcc275c513d1f8bc8dbd5732a4f01aad221d0426f271","login":"novotny1akub","name":"novotny1akub","bio":"","home_url":"","tier":"public"}},{"id":"a3b47b29df98c967","content":"I found it in another notebook https://observablehq.com/@john-guerra/multi-auto-select","node_id":2112,"create_time":"2022-10-03T11:04:17.683Z","update_time":null,"resolved":false,"user":{"id":"1125ba366576bacb","avatar_url":"https://avatars.observableusercontent.com/avatar/40e4321204a4470fbee5dcc275c513d1f8bc8dbd5732a4f01aad221d0426f271","login":"novotny1akub","name":"novotny1akub","bio":"","home_url":"","tier":"public"}}],"commenting_lock":null,"suggestions_to":[],"suggestion_from":null,"collections":[],"version":2286,"title":"Inputs","license":"mit","copyright":"Copyright 2018-2020 Jeremy Ashkenas","nodes":[{"id":0,"value":"md`# Inputs\n<div style=\"margin-top: -3px; font-size: 1.05em;\">*a.k.a “The Grand Native Inputs Bazaar”*</div>\n\n<img width=\"350px\" src=\"${await FileAttachment(\"capstan.gif\").url()}\" />\n\nA collection of assorted fancy inputs, odds and ends — with which to produce values to feed your burgeoning sketches. All inputs support optional **titles** and **descriptions**; where it makes sense, inputs also support a **submit** option, which allows you to prevent the value from updating until the input has been finalized.\n\nWares we have on offer: \n  * [\\`slider\\`](#sliderDemo)\n  * [\\`button\\`](#buttonDemo)\n  * [\\`select\\`](#selectDemo)\n  * [\\`autoSelect\\`](#autoSelectDemo)\n  * [\\`color\\`](#colorDemo)\n  * [\\`coordinates\\`](#coordinatesDemo)\n  * [\\`worldMapCoordinates\\`](#worldMapCoordinatesDemo)\n  * [\\`usaMapCoordinates\\`](#usaMapCoordinatesDemo)\n  * [\\`date\\`](#dateDemo)\n  * [\\`time\\`](#timeDemo)\n  * [\\`file\\`](#fileDemo)\n  * [\\`text\\`](#textDemo)\n  * [\\`textarea\\`](#textareaDemo)\n  * [\\`radio\\`](#radioDemo)\n  * [\\`checkbox\\`](#checkboxDemo)\n  * [\\`number\\`](#numberDemo)\n  * [\\`password\\`](#passwordDemo)`","pinned":false,"mode":"js","data":null,"name":null},{"id":2133,"value":"md`| <h3>Friends & Family:</h3>  |   |\n|---|---|\n| **[@mbostock/form-input](/@mbostock/form-input)**  | Fully custom forms, combining inputs into a single reactive cell. |\n| **[@mbostock/scrubber](/@mbostock/scrubber)** | A slider that automatically plays through its range, useful for driving and scrubbing through animations. |\n| **[@bumbeishvili/input-groups](/@bumbeishvili/input-groups)** | A wrapper function that can put many of these inputs into a more compact grid layout. | \n| **[@zechasault/color-schemes-and-interpolators-picker](/@zechasault/color-schemes-and-interpolators-picker)**  | Color scheme and interoplation pickers. |\n| **[@awhitty/fips-county-code-brush](/@awhitty/fips-county-code-brush)**  | A brushable map of the United States, allowing you to quickly select sets of counties to get their FIPS codes. |\n| **[@mootari/range-slider](https://observablehq.com/@mootari/range-slider)**  |  True range sliders, setting both a minimum and maximum value. |\n| **[@bumbeishvili/data-driven-range-sliders](/@bumbeishvili/data-driven-range-sliders)** | Data-driven range sliders, displaying a distribution histogram of the underlying data. |\n| **[@trebor/snapping-histogram-slider](/@trebor/snapping-histogram-slider)** | Another data-driven range slider option. |\n| **[@mootari’s 2D Slider](https://observablehq.com/d/98bbb19bf9e859ee)** | Two dimensional sliders, exploring discrete points on a plane. |\n| **[@yurivish/ternary-slider](/@yurivish/ternary-slider)** | Nifty ternary plot inputs, describing the percentages of a whole composed of exactly three things. |\n| **[@rreusser/binary-input](/@rreusser/binary-input)** | Input numbers in binary, great for working with values where results vary with specific bit positions. |\n| **[@bartok32/diy-inputs](/@bartok32/diy-inputs)** | A fun tool for defining your own fancy and colorful inputs. |\n| **[@bobkerns/elements-input](/@bobkerns/elements-input)** | A periodic table of the elements input! You can construct molecules programmatically, or click on the table to create formulas. |\n| **[@fil/selectflat](/@fil/selectflat)** | A fast selector to explore a discrete parameter space. The value changes on mouseover, and sticks when you click. |\n| **[@oscar6echo/player](/@oscar6echo/player)** | A slider with buttons to play, pause, step, and change speed and direction — useful for animations. |\n| **[@harrislapiroff/list-input](/@harrislapiroff/list-input)** | A input for when you want more than one of something. |\n| **[@nhogs/easing-graphs-editor](/@nhogs/easing-graphs-editor)** | A curve input to display and edit values of animated properties over time, such as easing curves and animation curves. |\n| **[@j-f1/checkbox](/@j-f1/checkbox)** | A simple checkbox input that provides a boolean value. |\n\n<br>*If you have any improvements for the bazaar, [please make your change in a fork and send it to me as a suggestion.](https://observablehq.com/@observablehq/suggestions-and-comments)*`","pinned":false,"mode":"js","data":null,"name":null},{"id":128,"value":"sliderDemo = md`---\n## Sliders\n\n~~~js\nimport {slider} from \"@jashkenas/inputs\"\n~~~`","pinned":false,"mode":"js","data":null,"name":null},{"id":26,"value":"viewof a = slider()","pinned":false,"mode":"js","data":null,"name":null},{"id":1492,"value":"viewof a1 = slider({\n  min: 0, \n  max: 1, \n  step: 0.01, \n  format: \".0%\",\n  description: \"Zero to one, formatted as a percentage\"\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":2106,"value":"viewof a1_1 = slider({\n  min: 0, \n  max: 1, \n  step: 0.01, \n  format: v => `${Math.round(100 * v)} per cent`,\n  description: \"Zero to one, formatted with a custom function\"\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":1539,"value":"viewof a2 = slider({\n  min: 0,\n  max: 1e9,\n  step: 1000,\n  value: 3250000,\n  format: \",\",\n  description:\n    \"Zero to one billion, in steps of one thousand, formatted as a (US) number\"\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":50,"value":"viewof a3 = slider({\n  min: 0, \n  max: 100, \n  step: 1, \n  value: 10, \n  title: \"Integers\", \n  description: \"Integers from zero through 100\"\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":120,"value":"viewof a4 = slider({\n  min: 0.9,\n  max: 1.1,\n  precision: 3,\n  description: \"A high precision slider example\"\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":553,"value":"viewof a5 = slider({\n  min: 0.9,\n  max: 1.1,\n  precision: 3,\n  submit: true,\n  description: \"The same as a4, but only changes value on submit\"\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":1591,"value":"md`More [fancy slider techniques](https://beta.observablehq.com/@mootari/prime-numbers-slider).`","pinned":false,"mode":"js","data":null,"name":null},{"id":6,"value":"function slider(config = {}) {\n  let {\n    min = 0,\n    max = 1,\n    value = (max + min) / 2,\n    step = \"any\",\n    precision = 2,\n    title,\n    description,\n    disabled,\n    getValue,\n    format,\n    display,\n    submit\n  } = typeof config === \"number\" ? { value: config } : config;\n  precision = Math.pow(10, precision);\n  if (!getValue)\n    getValue = input => Math.round(input.valueAsNumber * precision) / precision;\n  return input({\n    type: \"range\",\n    title,\n    description,\n    submit,\n    format,\n    display,\n    attributes: { min, max, step, disabled, value },\n    getValue\n  });\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":678,"value":"buttonDemo = md`---\n## Buttons\n\n~~~js\nimport {button} from \"@jashkenas/inputs\"\n~~~`","pinned":false,"mode":"js","data":null,"name":null},{"id":685,"value":"viewof b = button()","pinned":false,"mode":"js","data":null,"name":null},{"id":697,"value":"{\n  b\n  return !this;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":707,"value":"viewof b1 = button({value: \"Click me\", description: \"We use a reference to the button below to record the time you pressed it.\"})","pinned":false,"mode":"js","data":null,"name":null},{"id":714,"value":"{\n  b1;\n  return new Date(Date.now()).toUTCString()\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":682,"value":"function button(config = {}) {\n  const {\n    value = \"Ok\", title, description, disabled\n  } = typeof config === \"string\" ? {value: config} : config;\n  const form = input({\n    type: \"button\", title, description,\n    attributes: {disabled, value}\n  });\n  form.output.remove();\n  return form;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":913,"value":"selectDemo = md`---\n## Dropdown Menus and Multiselects\n\n~~~js\nimport {select} from \"@jashkenas/inputs\"\n~~~`","pinned":false,"mode":"js","data":null,"name":null},{"id":918,"value":"viewof dd = select([\"Spring\", \"Summer\", \"Fall\", \"Winter\"])","pinned":false,"mode":"js","data":null,"name":null},{"id":920,"value":"dd","pinned":false,"mode":"js","data":null,"name":null},{"id":947,"value":"viewof dd1 = select({\n  title: \"Stooges\",\n  description: \"Please pick your favorite stooge.\",\n  options: [\"Curly\", \"Larry\", \"Moe\", \"Shemp\"],\n  value: \"Moe\"\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":955,"value":"dd1","pinned":false,"mode":"js","data":null,"name":null},{"id":960,"value":"viewof dd2 = select({\n  description: \"As a child, which vegetables did you refuse to eat?\",\n  options: [\"Spinach\", \"Broccoli\", \"Brussels Sprouts\", \"Cauliflower\", \"Kale\", \"Turnips\", \"Green Beans\", \"Asparagus\"],\n  multiple: true\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":986,"value":"dd2","pinned":false,"mode":"js","data":null,"name":null},{"id":1524,"value":"viewof dd3 = {\n  const dd3 = select({\n    title: \"How are you feeling today?\",\n    options: [\n      { label: \"🤷\", value: \"shrug\" },\n      { label: \"😂\", value: \"tears-of-joy\" },\n      { label: \"😍\", value: \"loving-it\" },\n      { label: \"🤔\", value: \"hmmm\" },\n      { label: \"😱\", value: \"yikes\", disabled: true },\n      { label: \"😈\", value: \"mischievous\" },\n      { label: \"💩\", value: \"poo\" }\n    ],\n    value: \"hmmm\"\n  });\n  dd3.input.style.fontSize = \"30px\";\n  dd3.input.style.marginTop = \"8px\";\n  return dd3;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":1527,"value":"dd3","pinned":false,"mode":"js","data":null,"name":null},{"id":922,"value":"function select(config = {}) {\n  let {\n    value: formValue,\n    title,\n    description,\n    disabled,\n    submit,\n    multiple,\n    size,\n    options\n  } = Array.isArray(config) ? { options: config } : config;\n  options = options.map(o =>\n    typeof o === \"object\" ? o : { value: o, label: o }\n  );\n  const form = input({\n    type: \"select\",\n    title,\n    description,\n    submit,\n    attributes: { disabled },\n    getValue: input => {\n      const selected = Array.prototype.filter\n        .call(input.options, i => i.selected)\n        .map(i => i.value);\n      return multiple ? selected : selected[0];\n    },\n    form: html`\n      <form>\n        <select name=\"input\" ${\n          multiple ? `multiple size=\"${size || options.length}\"` : \"\"\n        }>\n          ${options.map(({ value, label,disabled }) =>\n            Object.assign(html`<option>`, {\n              value,\n              selected: Array.isArray(formValue)\n                ? formValue.includes(value)\n                : formValue === value,\n              disabled : disabled ? disabled : false,\n              textContent: label\n            })\n          )}\n        </select>\n      </form>\n    `\n  });\n  form.output.remove();\n  return form;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":2114,"value":"autoSelectDemo = md`---\n## Autoselects\n*A variant of an option menu, using an autocompleting text input, via HTML’s datalist element.* \n\n~~~js\nimport {autoSelect} from \"@jashkenas/inputs\"\n~~~`","pinned":false,"mode":"js","data":null,"name":null},{"id":2112,"value":"viewof as = autoSelect({\n  options: usa.objects.states.geometries.map(d => d.properties.name),\n  placeholder: \"Search for a US state . . .\"\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":2111,"value":"as","pinned":false,"mode":"js","data":null,"name":null},{"id":2110,"value":"function autoSelect(config = {}) {\n  const {\n    value,\n    title,\n    description,\n    disabled,\n    autocomplete = \"off\",\n    placeholder,\n    size,\n    options,\n    list = \"options\"\n  } = Array.isArray(config) ? { options: config } : config;\n\n  const optionsSet = new Set(options);\n\n  const form = input({\n    type: \"text\",\n    title,\n    description,\n    attributes: { disabled },\n    action: fm => {\n      fm.value = fm.input.value = value || \"\";\n      fm.onsubmit = e => e.preventDefault();\n      fm.input.oninput = function(e) {\n        e.stopPropagation();\n        fm.value = fm.input.value;\n        if (!fm.value || optionsSet.has(fm.value))\n          fm.dispatchEvent(new CustomEvent(\"input\"));\n      };\n    },\n    form: html`\n      <form>\n         <input name=\"input\" type=\"text\" autocomplete=\"off\" \n          placeholder=\"${placeholder ||\n            \"\"}\" style=\"font-size: 1em;\" list=${list}>\n          <datalist id=\"${list}\">\n              ${options.map(d =>\n                Object.assign(html`<option>`, {\n                  value: d\n                })\n              )}\n          </datalist>\n      </form>\n      `\n  });\n\n  form.output.remove();\n  return form;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":153,"value":"colorDemo = md`---\n## Color Pickers\n\n*value: a hexadecimal string, e.g. * \\`\"#bada55\"\\` \n\n~~~js\nimport {color} from \"@jashkenas/inputs\"\n~~~`","pinned":false,"mode":"js","data":null,"name":null},{"id":141,"value":"viewof c = color()","pinned":false,"mode":"js","data":null,"name":null},{"id":165,"value":"viewof c1 = color({\n  value: \"#0000ff\",\n  title: \"Background Color\",\n  description: \"This color picker starts out blue\"\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":130,"value":"function color(config = {}) {\n  const { value = \"#000000\", title, description, disabled, submit, display } =\n    typeof config === \"string\" ? { value: config } : config;\n  const form = input({\n    type: \"color\",\n    title,\n    description,\n    submit,\n    display,\n    attributes: { disabled, value }\n  });\n  // The following two lines are a bugfix for Safari, which hopefully can be removed in the future.\n  form.input.value = '';\n  form.input.value = value;\n  if (title || description) form.input.style.margin = \"5px 0\";\n  return form;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":1694,"value":"coordinatesDemo = md` ---\n## Coordinates\n\n*value: an array pair of \\`[longitude, latitude]\\`, e.g. * \\`[-122.27, 37.87]\\` \n\n~~~js\nimport {coordinates} from \"@jashkenas/inputs\"\n~~~`","pinned":false,"mode":"js","data":null,"name":null},{"id":1784,"value":"viewof coords1 = coordinates()","pinned":false,"mode":"js","data":null,"name":null},{"id":1786,"value":"coords1","pinned":false,"mode":"js","data":null,"name":null},{"id":1706,"value":"viewof coords2 = coordinates({\n  title: \"Hometown\",\n  description: \"Enter the coordinates of where you were born\",\n  value: [-122.27, 37.87],\n  submit: true\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":1740,"value":"coords2","pinned":false,"mode":"js","data":null,"name":null},{"id":1698,"value":"function coordinates(config = {}) {\n  const { value = [], title, description, submit } = Array.isArray(config)\n    ? { value: config }\n    : config;\n  let [lon, lat] = value;\n  lon = lon != null ? lon : \"\";\n  lat = lat != null ? lat : \"\";\n  const lonEl = html`<input name=\"input\" type=\"number\" autocomplete=\"off\" min=\"-180\" max=\"180\" style=\"width: 80px;\" step=\"any\" value=\"${lon}\" />`;\n  const latEl = html`<input name=\"input\" type=\"number\" autocomplete=\"off\" min=\"-90\" max=\"90\" style=\"width: 80px;\" step=\"any\" value=\"${lat}\" />`;\n  const form = input({\n    type: \"coordinates\",\n    title,\n    description,\n    submit,\n    getValue: () => {\n      const lon = lonEl.valueAsNumber;\n      const lat = latEl.valueAsNumber;\n      return [isNaN(lon) ? null : lon, isNaN(lat) ? null : lat];\n    },\n    form: html`\n      <form>\n        <label style=\"display: inline-block; font: 600 0.8rem sans-serif; margin: 6px 0 3px;\">\n          <span style=\"display: inline-block; width: 70px;\">Longitude:</span>\n          ${lonEl}\n        </label>\n        <br>\n        <label style=\"display: inline-block; font: 600 0.8rem sans-serif; margin: 0 0 6px;\">\n          <span style=\"display: inline-block; width: 70px;\">Latitude:</span>\n          ${latEl}\n        </label>\n      </form>\n    `\n  });\n  form.output.remove();\n  return form;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":1827,"value":"worldMapCoordinatesDemo = md` ---\n## World Map Coordinates\n\n*value: an array pair of \\`[longitude, latitude]\\`, e.g. * \\`[-122.27, 37.87]\\` \n\n~~~js\nimport {worldMapCoordinates} from \"@jashkenas/inputs\"\n~~~`","pinned":false,"mode":"js","data":null,"name":null},{"id":1834,"value":"viewof worldMap1 = worldMapCoordinates([-122.27, 37.87])","pinned":false,"mode":"js","data":null,"name":null},{"id":1916,"value":"worldMap1","pinned":false,"mode":"js","data":null,"name":null},{"id":1829,"value":"function worldMapCoordinates(config = {}) {\n  const {\n    value = [], title, description, width = 400\n  } = Array.isArray(config) ? {value: config} : config;\n  const height = Math.round((210 / 400) * width);\n  let [lon, lat] = value;\n  lon = lon != null ? lon : null;\n  lat = lat != null ? lat : null;\n  const formEl = html`<form style=\"width: ${width}px;\"></form>`;\n  const context = DOM.context2d(width, height);\n  const canvas = context.canvas;\n  canvas.style.margin = \"10px 0 3px\";\n  const projection = d3geo\n    .geoNaturalEarth1()\n    .precision(0.1)\n    .fitSize([width, height], { type: \"Sphere\" });\n  const path = d3geo.geoPath(projection, context).pointRadius(2.5);\n  formEl.append(canvas);\n\n  function draw() {\n    context.fillStyle = \"#fff\";\n    context.fillRect(0, 0, width, height);\n    context.beginPath();\n    path(graticule);\n    context.lineWidth = 0.35;\n    context.strokeStyle = `#ddd`;\n    context.stroke();\n    context.beginPath();\n    path(land);\n    context.fillStyle = `#f4f4f4`;\n    context.fill();\n    context.beginPath();\n    path(countries);\n    context.strokeStyle = `#aaa`;\n    context.stroke();\n    if (lon != null && lat != null) {\n      const pointPath = { type: \"MultiPoint\", coordinates: [[lon, lat]] };\n      context.beginPath();\n      path(pointPath);\n      context.fillStyle = `#f00`;\n      context.fill();\n    }\n  }\n\n  canvas.onclick = function(ev) {\n    const { offsetX, offsetY } = ev;\n    var coords = projection.invert([offsetX, offsetY]);\n    lon = +coords[0].toFixed(2);\n    lat = +coords[1].toFixed(2);\n    draw();\n    canvas.dispatchEvent(new CustomEvent(\"input\", { bubbles: true }));\n  };\n\n  draw();\n\n  const form = input({\n    type: \"worldMapCoordinates\",\n    title,\n    description,\n    display: v =>\n      html`<div style=\"width: ${width}px; white-space: nowrap; color: #444; text-align: center; font: 13px sans-serif; margin-bottom: 5px;\">\n            <span style=\"color: #777;\">Longitude:</span> ${lon != null ? lon.toFixed(2) : \"\"}\n            &nbsp; &nbsp; \n            <span style=\"color: #777;\">Latitude:</span> ${lat != null ? lat.toFixed(2) : \"\"} \n          </div>`,\n    getValue: () => [lon != null ? lon : null, lat != null ? lat : null],\n    form: formEl\n  });\n  return form;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":1967,"value":"usaMapCoordinatesDemo = md` ---\n## U.S.A. Map Coordinates\n\n*value: an array pair of \\`[longitude, latitude]\\`, e.g. * \\`[-122.27, 37.87]\\` \n\n~~~js\nimport {usaMapCoordinates} from \"@jashkenas/inputs\"\n~~~`","pinned":false,"mode":"js","data":null,"name":null},{"id":1985,"value":"viewof usaMap1 = usaMapCoordinates([-122.27, 37.87])","pinned":false,"mode":"js","data":null,"name":null},{"id":1986,"value":"usaMap1","pinned":false,"mode":"js","data":null,"name":null},{"id":2032,"value":"viewof usaMap2 = usaMapCoordinates({\n  title: \"A Mini Map\",\n  description: \"Defaults to New York City\",\n  width: 200,\n  value: [-74, 40.71]\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":2049,"value":"usaMap2","pinned":false,"mode":"js","data":null,"name":null},{"id":1982,"value":"function usaMapCoordinates(config = {}) {\n  const {\n    value = [], title, description, width = 400\n  } = Array.isArray(config) ? {value: config} : config;\n  const scale = width / 960;\n  const height = scale * 600;\n  let [lon, lat] = value;\n  lon = lon != null ? lon : null;\n  lat = lat != null ? lat : null;\n  const formEl = html`<form style=\"width: ${width}px;\"></form>`;\n  const context = DOM.context2d(width, height);\n  const canvas = context.canvas;\n  canvas.style.margin = \"5px 0 20px\";\n  const projection = d3geo\n    .geoAlbersUsa()\n    .scale(1280)\n    .translate([480, 300]);\n  const path = d3geo\n    .geoPath()\n    .context(context)\n    .pointRadius(2.5 / scale);\n  formEl.append(canvas);\n\n  function draw() {\n    context.clearRect(0, 0, width, height);\n    context.save();\n    context.scale(scale, scale);\n    context.lineWidth = 0.35 / scale;\n    context.beginPath();\n    path(nation);\n    context.fillStyle = `#f4f4f4`;\n    context.fill();\n    context.beginPath();\n    path(states);\n    context.strokeStyle = `#aaa`;\n    context.stroke();\n    if (lon != null && lat != null) {\n      const pointPath = {\n        type: \"MultiPoint\",\n        coordinates: [projection([lon, lat])]\n      };\n      context.beginPath();\n      path(pointPath);\n      context.fillStyle = `#f00`;\n      context.fill();\n    }\n    context.restore();\n  }\n\n  canvas.onclick = function(ev) {\n    const { offsetX, offsetY } = ev;\n    var coords = projection.invert([offsetX / scale, offsetY / scale]);\n    lon = +coords[0].toFixed(2);\n    lat = +coords[1].toFixed(2);\n    draw();\n    canvas.dispatchEvent(new CustomEvent(\"input\", { bubbles: true }));\n  };\n\n  draw();\n\n  const form = input({\n    type: \"worldMapCoordinates\",\n    title,\n    description,\n    display: v =>\n      html`<div style=\"position: absolute; width: ${width}px; white-space: nowrap; color: #444; text-align: center; font: 13px sans-serif; margin-top: -18px;\">\n            <span style=\"color: #777;\">Longitude:</span> ${lon != null ? lon : \"\"}\n            &nbsp; &nbsp; \n            <span style=\"color: #777;\">Latitude:</span> ${lat != null ? lat : \"\"} \n          </div>`,\n    getValue: () => [lon != null ? lon : null, lat != null ? lat : null],\n    form: formEl\n  });\n  return form;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":193,"value":"dateDemo = md` ---\n## Dates\n\n*value: a YYYY-MM-DD formatted string: * \\`\"2016-11-08\"\\` \n\n~~~js\nimport {date} from \"@jashkenas/inputs\"\n~~~`","pinned":false,"mode":"js","data":null,"name":null},{"id":208,"value":"viewof d = date()","pinned":false,"mode":"js","data":null,"name":null},{"id":210,"value":"viewof d1 = date({\n  title: \"2017\", \n  min: \"2017-01-01\",\n  max: \"2017-12-31\",\n  value: \"2017-01-01\",\n  description: \"Only dates within the 2017 calendar year are allowed\"\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":200,"value":"function date(config = {}) {\n  const { min, max, value, title, description, disabled, display } =\n    typeof config === \"string\" ? { value: config } : config;\n  return input({\n    type: \"date\",\n    title,\n    description,\n    display,\n    attributes: { min, max, disabled, value }\n  });\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":2101,"value":"timeDemo = md` ---\n## Times\n\n*value: a HH:MM:SS formatted string: * \\`\"09:30:45\"\\`\n<br>*(Time values are always in 24-hour format)*\n\n~~~js\nimport {time} from \"@jashkenas/inputs\"\n~~~`","pinned":false,"mode":"js","data":null,"name":null},{"id":2100,"value":"viewof t = time()","pinned":false,"mode":"js","data":null,"name":null},{"id":2099,"value":"t","pinned":false,"mode":"js","data":null,"name":null},{"id":2098,"value":"viewof t1 = time({\n  title: \"Afternoon\",\n  min: \"12:00:00\",\n  max: \"23:59:59\",\n  value: \"13:00:00\",\n  step: 1,\n  description: \"Only times after noon are allowed, and seconds are included\"\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":2097,"value":"t1","pinned":false,"mode":"js","data":null,"name":null},{"id":2096,"value":"function time(config = {}) {\n  const { min, max, step, value, title, description, disabled, display } =\n    typeof config === \"string\" ? { value: config } : config;\n  const el = input({\n    type: \"time\",\n    title,\n    description,\n    display,\n    getValue: d => (d.value ? d.value : undefined),\n    attributes: { min, max, step, disabled, value }\n  });\n  el.output.remove();\n  return el;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":249,"value":"fileDemo = md`---\n## File Upload\n*Use the JavaScript [File API](https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications) to work with uploaded file contents.*\n\n\\`import {file} from \"@jashkenas/inputs\"\\``","pinned":false,"mode":"js","data":null,"name":null},{"id":257,"value":"viewof e = file()","pinned":false,"mode":"js","data":null,"name":null},{"id":297,"value":"viewof e1 = file({\n  title: \"Photographs\",\n  description: \"Only .jpg files are allowed in this example. Choose some images, and they’ll appear in the cell below.\",\n  accept: \".jpg\",\n  multiple: true,\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":1701,"value":"{\n  const div = html`<div>`;\n  for (var j = 0; j < e1.length; j++) {\n    let file = e1[j];\n    let img = html`<img height=\"125px\" style=\"margin: 2px;\" />`;\n    img.src = await Files.url(e1[j]);\n    div.append(img);\n  }\n  return div;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":252,"value":"function file(config = {}) {\n  const { multiple, accept, title, description, disabled } = config;\n  const form = input({\n    type: \"file\",\n    title,\n    description,\n    attributes: { multiple, accept, disabled },\n    action: form => {\n      form.input.onchange = () => {\n        form.value = multiple ? form.input.files : form.input.files[0];\n        form.dispatchEvent(new CustomEvent(\"input\"));\n      };\n    }\n  });\n  form.output.remove();\n  form.input.onchange();\n  return form;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":433,"value":"textDemo = md`---\n## Text Inputs\n\n~~~js\nimport {text} from \"@jashkenas/inputs\"\n~~~`","pinned":false,"mode":"js","data":null,"name":null},{"id":442,"value":"viewof f = text()","pinned":false,"mode":"js","data":null,"name":null},{"id":474,"value":"viewof f1 = text({title: \"A Text Input\", placeholder: \"Placeholder text\", description: \"Note that text inputs don’t show output on the right\"})","pinned":false,"mode":"js","data":null,"name":null},{"id":576,"value":"f1","pinned":false,"mode":"js","data":null,"name":null},{"id":571,"value":"viewof f2 = text({placeholder: \"Placeholder text\", description: \"This input only changes value on submit\", submit: \"Go\"})","pinned":false,"mode":"js","data":null,"name":null},{"id":578,"value":"f2","pinned":false,"mode":"js","data":null,"name":null},{"id":435,"value":"function text(config = {}) {\n  const {\n    value,\n    title,\n    description,\n    disabled,\n    autocomplete = \"off\",\n    maxlength,\n    minlength,\n    pattern,\n    placeholder,\n    size,\n    submit,\n    getValue\n  } = typeof config === \"string\" ? { value: config } : config;\n  const form = input({\n    type: \"text\",\n    title,\n    description,\n    submit,\n    getValue,\n    attributes: {\n      value,\n      autocomplete,\n      maxlength,\n      minlength,\n      pattern,\n      placeholder,\n      size,\n      disabled\n    }\n  });\n  form.output.remove();\n  form.input.style.fontSize = \"1em\";\n  return form;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":482,"value":"textareaDemo = md`---\n## Textareas\n\n~~~js\nimport {textarea} from \"@jashkenas/inputs\"\n~~~`","pinned":false,"mode":"js","data":null,"name":null},{"id":489,"value":"viewof g = textarea()","pinned":false,"mode":"js","data":null,"name":null},{"id":619,"value":"g","pinned":false,"mode":"js","data":null,"name":null},{"id":520,"value":"viewof g1 = textarea({\n  title: \"Your Great American Novel\", \n  placeholder: \"Insert story here...\", \n  spellcheck: true,\n  width: \"100%\",\n  rows: 10,\n  submit: \"Publish\"\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":617,"value":"g1","pinned":false,"mode":"js","data":null,"name":null},{"id":485,"value":"function textarea(config = {}) {\n  const {\n    value = \"\",\n    title,\n    description,\n    autocomplete,\n    cols = 45,\n    rows = 3,\n    width,\n    height,\n    maxlength,\n    placeholder,\n    spellcheck,\n    wrap,\n    submit,\n    disabled,\n    getValue\n  } = typeof config === \"string\" ? { value: config } : config;\n  const form = input({\n    form: html`<form><textarea style=\"display: block; font-size: 0.8em;\" name=input>${value}</textarea></form>`,\n    title,\n    description,\n    submit,\n    getValue,\n    attributes: {\n      autocomplete,\n      cols,\n      rows,\n      maxlength,\n      placeholder,\n      spellcheck,\n      wrap,\n      disabled\n    }\n  });\n  form.output.remove();\n  if (width != null) form.input.style.width = width;\n  if (height != null) form.input.style.height = height;\n  if (submit) form.submit.style.margin = \"0\";\n  if (title || description) form.input.style.margin = \"3px 0\";\n  return form;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":764,"value":"radioDemo = md`---\n## Radio Buttons\n\n~~~js\nimport {radio} from \"@jashkenas/inputs\"\n~~~`","pinned":false,"mode":"js","data":null,"name":null},{"id":831,"value":"viewof r = radio([\"Lust\", \"Gluttony\", \"Greed\", \"Sloth\", \"Wrath\", \"Envy\", \"Pride\"])","pinned":false,"mode":"js","data":null,"name":null},{"id":835,"value":"r","pinned":false,"mode":"js","data":null,"name":null},{"id":780,"value":"viewof r1 = radio({\n  title: 'Contact Us',\n  description: 'Please select your preferred contact method',\n  options: [\n    { label: 'By Email', value: 'email' },\n    { label: 'By Phone', value: 'phone' },\n    { label: 'By Pager', value: 'pager' },\n  ],\n  value: 'pager'\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":793,"value":"r1","pinned":false,"mode":"js","data":null,"name":null},{"id":761,"value":"function radio(config = {}) {\n  let {\n    value: formValue,\n    title,\n    description,\n    submit,\n    options,\n    disabled\n  } = Array.isArray(config) ? { options: config } : config;\n  options = options.map(o =>\n    typeof o === \"string\" ? { value: o, label: o } : o\n  );\n  const form = input({\n    type: \"radio\",\n    title,\n    description,\n    submit,\n    getValue: input => {\n      if (input.checked) return input.value;\n      const checked = Array.prototype.find.call(input, radio => radio.checked);\n      return checked ? checked.value : undefined;\n    },\n    form: html`\n      <form>\n        ${options.map(({ value, label }, i) => {\n          const input = html`<input type=radio name=input ${\n            value === formValue ? \"checked\" : \"\"\n          } style=\"vertical-align: top; ${\n            i === 0 ? `margin-left: 1px;` : ``\n          }\" />`;\n          input.setAttribute(\"value\", value);\n          if (disabled) input.setAttribute(\"value\", disabled);\n          const tag = html`\n          <label style=\"display: inline-block; margin: 5px 10px 3px 0; font-size: 0.85em;\">\n           ${input}\n           ${label}\n          </label>`;\n          return tag;\n        })}\n      </form>\n    `\n  });\n  form.output.remove();\n  return form;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":840,"value":"checkboxDemo = md`---\n## Checkboxes\n\n~~~js\nimport {checkbox} from \"@jashkenas/inputs\"\n~~~`","pinned":false,"mode":"js","data":null,"name":null},{"id":858,"value":"viewof ch = checkbox([\"Lust\", \"Gluttony\", \"Greed\", \"Sloth\", \"Wrath\", \"Envy\", \"Pride\"])","pinned":false,"mode":"js","data":null,"name":null},{"id":864,"value":"ch","pinned":false,"mode":"js","data":null,"name":null},{"id":852,"value":"viewof ch1 = checkbox({\n  title: \"Colors\",\n  description: \"Please select your favorite colors\",\n  options: [\n    { value: \"r\", label: \"Red\" },\n    { value: \"o\", label: \"Orange\" },\n    { value: \"y\", label: \"Yellow\" },\n    { value: \"g\", label: \"Green\" },\n    { value: \"b\", label: \"Blue\" },\n    { value: \"i\", label: \"Indigo\" },\n    { value: \"v\", label: \"Violet\" }\n  ],\n  value: [\"r\", \"g\", \"b\"],\n  submit: true\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":856,"value":"ch1","pinned":false,"mode":"js","data":null,"name":null},{"id":871,"value":"viewof ch3 = checkbox({\n  description: \"Just a single checkbox to toggle\",\n  options: [{ value: \"toggle\", label: \"On\" }],\n  value: \"toggle\"\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":874,"value":"ch3","pinned":false,"mode":"js","data":null,"name":null},{"id":844,"value":"function checkbox(config = {}) {\n  let {\n    value: formValue,\n    title,\n    description,\n    submit,\n    disabled,\n    options\n  } = Array.isArray(config) ? { options: config } : config;\n  options = options.map(o =>\n    typeof o === \"string\" ? { value: o, label: o } : o\n  );\n  const form = input({\n    type: \"checkbox\",\n    title,\n    description,\n    submit,\n    getValue: input => {\n      if (input.length)\n        return Array.prototype.filter\n          .call(input, i => i.checked)\n          .map(i => i.value);\n      return input.checked ? input.value : false;\n    },\n    form: html`\n      <form>\n        ${options.map(({ value, label }, i) => {\n          const input = html`<input type=checkbox name=input ${\n            (formValue || []).indexOf(value) > -1 ? \"checked\" : \"\"\n          } style=\"vertical-align: top; ${\n            i === 0 ? `margin-left: 1px;` : ``\n          }\" />`;\n          input.setAttribute(\"value\", value);\n          if (disabled) input.setAttribute(\"disabled\", disabled);\n          const tag = html`<label style=\"display: inline-block; margin: 5px 10px 3px 0; font-size: 0.85em;\">\n           ${input}\n           ${label}\n          </label>`;\n          return tag;\n        })}\n      </form>\n    `\n  });\n  form.output.remove();\n  return form;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":630,"value":"numberDemo = md`---\n## Numbers\n\n~~~js\nimport {number} from \"@jashkenas/inputs\"\n~~~`","pinned":false,"mode":"js","data":null,"name":null},{"id":640,"value":"viewof h = number()","pinned":false,"mode":"js","data":null,"name":null},{"id":662,"value":"h","pinned":false,"mode":"js","data":null,"name":null},{"id":650,"value":"viewof h1 = number({placeholder: \"13+\", title: \"Your Age\", submit: true})","pinned":false,"mode":"js","data":null,"name":null},{"id":656,"value":"h1","pinned":false,"mode":"js","data":null,"name":null},{"id":636,"value":"function number(config = {}) {\n  const {\n    value,\n    title,\n    description,\n    disabled,\n    placeholder,\n    submit,\n    step = \"any\",\n    min,\n    max\n  } =\n    typeof config === \"number\" || typeof config === \"string\"\n      ? { value: +config }\n      : config;\n  const form = input({\n    type: \"number\",\n    title,\n    description,\n    submit,\n    attributes: {\n      value,\n      placeholder,\n      step,\n      min,\n      max,\n      autocomplete: \"off\",\n      disabled\n    },\n    getValue: input => input.valueAsNumber\n  });\n  form.output.remove();\n  form.input.style.width = \"auto\";\n  form.input.style.fontSize = \"1em\";\n  return form;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":1626,"value":"passwordDemo = md`---\n## Passwords\n\n~~~js\nimport {password} from \"@jashkenas/inputs\"\n~~~`","pinned":false,"mode":"js","data":null,"name":null},{"id":1629,"value":"viewof i = password({value: \"password\"})","pinned":false,"mode":"js","data":null,"name":null},{"id":1635,"value":"i","pinned":false,"mode":"js","data":null,"name":null},{"id":1638,"value":"viewof i1 = password({\n  title: \"Your super secret password\", \n  description: \"Less than 12 characters, please.\",\n  minlength: 6,\n  maxlength: 12\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":1641,"value":"i1","pinned":false,"mode":"js","data":null,"name":null},{"id":1624,"value":"function password(config = {}) {\n  const {\n    value,\n    title,\n    description,\n    disabled,\n    autocomplete = \"off\",\n    maxlength,\n    minlength,\n    pattern,\n    placeholder,\n    size,\n    submit\n  } = typeof config === \"string\" ? { value: config } : config;\n  const form = input({\n    type: \"password\",\n    title,\n    description,\n    submit,\n    attributes: {\n      value,\n      autocomplete,\n      maxlength,\n      minlength,\n      pattern,\n      placeholder,\n      size,\n      disabled\n    }\n  });\n  form.output.remove();\n  form.input.style.fontSize = \"1em\";\n  return form;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":1684,"value":"md`---\n## Wishlist (Send suggestions, please!)\n\n* 3D coordinate input (for say, positioning a camera in a WebGL sketch)\n* Geocoder search with location autocomplete that returns longitude and latitude.\n* Degrees or radians input, for circular things, or angles.\n* A dimensions input, or a box-model input, with margin (and optionally, padding).\n* A map-projection-picker input, rendering little thumbnails of all the d3-geo-projections.\n* Drag and drop file upload input.\n* Alternative coordinate inputs, e.g. Right Ascension, Declination.\n* Other useful formatting options.\n\n---`","pinned":false,"mode":"js","data":null,"name":null},{"id":376,"value":"function input(config) {\n  let {\n    form,\n    type = \"text\",\n    attributes = {},\n    action,\n    getValue,\n    title,\n    description,\n    format,\n    display,\n    submit,\n    options\n  } = config;\n  const wrapper = html`<div></div>`;\n  if (!form)\n    form = html`<form>\n\t<input name=input type=${type} />\n  </form>`;\n  Object.keys(attributes).forEach(key => {\n    const val = attributes[key];\n    if (val != null) form.input.setAttribute(key, val);\n  });\n  if (submit)\n    form.append(\n      html`<input name=submit type=submit style=\"margin: 0 0.75em\" value=\"${\n        typeof submit == \"string\" ? submit : \"Submit\"\n      }\" />`\n    );\n  form.append(\n    html`<output name=output style=\"font: 14px Menlo, Consolas, monospace; margin-left: 0.5em;\"></output>`\n  );\n  if (title)\n    form.prepend(\n      html`<div style=\"font: 700 0.9rem sans-serif; margin-bottom: 3px;\">${title}</div>`\n    );\n  if (description)\n    form.append(\n      html`<div style=\"font-size: 0.85rem; font-style: italic; margin-top: 3px;\">${description}</div>`\n    );\n  if (format)\n    format = typeof format === \"function\" ? format : d3format.format(format);\n  if (action) {\n    action(form);\n  } else {\n    const verb = submit\n      ? \"onsubmit\"\n      : type == \"button\"\n      ? \"onclick\"\n      : type == \"checkbox\" || type == \"radio\"\n      ? \"onchange\"\n      : \"oninput\";\n    form[verb] = e => {\n      e && e.preventDefault();\n      const value = getValue ? getValue(form.input) : form.input.value;\n      if (form.output) {\n        const out = display ? display(value) : format ? format(value) : value;\n        if (out instanceof window.Element) {\n          while (form.output.hasChildNodes()) {\n            form.output.removeChild(form.output.lastChild);\n          }\n          form.output.append(out);\n        } else {\n          form.output.value = out;\n        }\n      }\n      form.value = value;\n      if (verb !== \"oninput\")\n        form.dispatchEvent(new CustomEvent(\"input\", { bubbles: true }));\n    };\n    if (verb !== \"oninput\")\n      wrapper.oninput = e => e && e.stopPropagation() && e.preventDefault();\n    if (verb !== \"onsubmit\") form.onsubmit = e => e && e.preventDefault();\n    form[verb]();\n  }\n  while (form.childNodes.length) {\n    wrapper.appendChild(form.childNodes[0]);\n  }\n  form.append(wrapper);\n  return form;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":1823,"value":"d3geo = require(\"d3-geo@1\")","pinned":false,"mode":"js","data":null,"name":null},{"id":1475,"value":"d3format = require(\"d3-format@1\")","pinned":false,"mode":"js","data":null,"name":null},{"id":1825,"value":"topojson = require(\"topojson-client@3\")","pinned":false,"mode":"js","data":null,"name":null},{"id":1820,"value":"world = (await fetch(\"https://cdn.jsdelivr.net/npm/world-atlas@1/world/110m.json\")).json()","pinned":false,"mode":"js","data":null,"name":null},{"id":1841,"value":"land = topojson.feature(world, world.objects.land)","pinned":false,"mode":"js","data":null,"name":null},{"id":1840,"value":"countries = topojson.feature(world, world.objects.countries)","pinned":false,"mode":"js","data":null,"name":null},{"id":1958,"value":"usa = (await fetch(\"https://cdn.jsdelivr.net/npm/us-atlas@^2.1/us/states-10m.json\")).json()","pinned":false,"mode":"js","data":null,"name":null},{"id":1961,"value":"nation = topojson.feature(usa, usa.objects.nation)","pinned":false,"mode":"js","data":null,"name":null},{"id":1963,"value":"states = topojson.feature(usa, usa.objects.states)","pinned":false,"mode":"js","data":null,"name":null},{"id":1845,"value":"graticule = d3geo.geoGraticule10()","pinned":false,"mode":"js","data":null,"name":null},{"id":1686,"value":"viewof license = {\n  const license = md`License: [MIT](https://opensource.org/licenses/MIT)`;\n  license.value = \"MIT\";\n  return license;\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":228,"value":"md`*Clip art courtesy [ClipArt ETC](https://etc.usf.edu/clipart/), radio buttons and checkboxes courtesy [Amit Sch](https://beta.observablehq.com/@meetamit/multiple-choice-inputs).*`","pinned":false,"mode":"js","data":null,"name":null}],"resolutions":[],"schedule":null,"last_view_time":null}