{"componentChunkName":"component---src-components-tutorials-js","path":"/tutorials/listbox-widget/","result":{"data":{"markdownRemark":{"html":"<h2>Contents</h2>\n<ol>\n<li><a href=\"#about\">Why would I need this?</a></li>\n<li>\n<p><a href=\"#work\">How does the listbox widget work?</a></p>\n<ol>\n<li>\n<p><a href=\"#work-r\">Building the R Component</a></p>\n<ol>\n<li><a href=\"#work-r-listbox-toggle\">Listbox Toggle</a></li>\n<li><a href=\"#work-r-listbox-options\">Listbox Options</a></li>\n<li><a href=\"#work-r-listbox-list\">Listbox List</a></li>\n<li><a href=\"#work-r-listbox\">Main Listbox function</a></li>\n</ol>\n</li>\n<li>\n<p><a href=\"#work-js\">Creating the JavaScript Input Bindings</a></p>\n<ol>\n<li><a href=\"#work-js-initialize\">initialize</a></li>\n<li><a href=\"#work-js-getValue\">getValue</a></li>\n<li><a href=\"#work-js-subscribe\">subscribe</a></li>\n</ol>\n</li>\n</ol>\n</li>\n<li><a href=\"#know\">What do I need to know before I integrate this into my app?</a></li>\n<li><a href=\"#run\">How do I run the demo</a></li>\n<li><a href=\"#further-reading\">Further reading</a></li>\n</ol>\n<!-- endexcerpt -->\n<span id=\"about\" />\n<h2>Why would I need this?</h2>\n<p>In the post <a href=\"./../select-input-styling/\">Custom Select Inputs</a>, I demonstrated the use of the <code>appearance</code> CSS property for styling select inputs. However, that approach can cause the element to render differently across browsers making the web experience inconsistent. Using a well-designed component library will help with this, but it usually involves loading a large library into your app just to use a single component. Other solutions involve some creative markup and CSS, but it is not guaranteed that these approaches are accessible for individuals who use assistive web devices. Instead, it is possible to create your own dropdown menu by creating using the <a href=\"https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/listbox_role\">listbox</a> role.</p>\n<p>In this post, I will provide an overview for creating your own listbox widget using HTML, CSS, and JavaScript. The Web Accessibility Initiative's (WAI) Authoring Practices for creating a <a href=\"https://www.w3.org/TR/wai-aria-practices/#Listbox\">listbox widget</a> is used to ensure the widget follows recommended accessibility practices. The example discussed in the post reworks the <a href=\"https://www.w3.org/TR/wai-aria-practices/examples/listbox/listbox-collapsible.html\">Collapsible Dropdown Listbox Example</a> for use in Shiny applications, including writing the R functions that generate the HTML and creating the custom JavaScript input binding that handles the communication between R and the listbox widget.</p>\n<blockquote>\n<p>This tutorial focuses heavily on HTML and JavaScript. Some experience will definitely help, but it is not required. I have tried to keep concepts simple and reference outside sources where possible. If you notice any errors or have suggestions for improving this post, feel free to open a new <a href=\"https://github.com/davidruvolo51/shinytutorials/issues\">issue</a> on GitHub.</p>\n</blockquote>\n<span id=\"work\" />\n<h2>How does the listbox widget work?</h2>\n<p>In this post, I will cover the basics for creating the listbox widget.</p>\n<ol>\n<li>Building the R component</li>\n<li>Creating the JavaScript input binding</li>\n</ol>\n<p>Before we dive in, let's create the required files. Add the following files to your Shiny project.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">my-project/\n  R/\n    listbox.R\n  www/\n    css / \n      listbox.css\n    js/\n      listbox.js\n  ...</code></pre></div>\n<p>You can place the CSS and JS files wherever you like as long as they are in the <code>www</code> folder. As of Shiny 1.5, files located in the <code>R/</code> folder are loaded automatically. </p>\n<p>Checkout the <a href=\"https://github.com/davidruvolo51/shinyAppTutorials/tree/prod/shiny-listbox\">listbox sub-repository</a> on GitHub for CSS code. I wanted to keep this post short and focus mainly on the HTML and JavaScript code. All styles were written in SASS and compiled to CSS using the application bundler <a href=\"http://parceljs.org\">Parcel</a>. The CSS file is located in the file <a href=\"https://github.com/davidruvolo51/shinyAppTutorials/blob/prod/shiny-listbox/src/listbox.scss\"><code>src/listbox.scss</code></a> and the compiled CSS file can be found at <a href=\"https://github.com/davidruvolo51/shinyAppTutorials/blob/prod/shiny-listbox/www/css/listbox.css\"><code>www/css/listbox.css</code></a>. If you are using vanilla CSS, load the <code>listbox.css</code> file directly into your app or copy the contents into your app's primary CSS file.</p>\n<span id=\"work-r\" />\n<h3>Building the R component</h3>\n<p>In this section, we will be working from the <code>listbox.R</code> file.</p>\n<p>First, we will write the R functions that render the HTML markup and required attributes for the listbox widget. Using the <a href=\"https://www.w3.org/TR/wai-aria-practices/examples/listbox/listbox-collapsible.html\">Collapsible Dropdown Listbox Example</a> as a guide, the markup requires a several HTML elements and ARIA attributes. Take a look at the example's <a href=\"https://www.w3.org/TR/wai-aria-practices/examples/listbox/listbox-collapsible.html#sc\">HTML source code</a> as this will help determine what the R functions should return.</p>\n<ul>\n<li>Container: In the example, they used a <code>&#x3C;div></code> element to wrap the component. We can use a <code>&#x3C;div></code> as the listbox container, but I opted for the <code>&#x3C;fieldset></code> element as I would primarily use the listbox element inside a <code>&#x3C;form></code>. The <code>&#x3C;fieldset></code> element can be accessed using the <code>tags$fieldset</code> object.</li>\n<li>Title: The title describes the listbox widget and its elements. Since I am using the <code>&#x3C;fieldset></code> element, then <code>&#x3C;legend></code> is the most appropriate element. (Accessed by <code>tags$legend</code>)</li>\n<li>Label: A label may also be useful as it provides additional context for the listbox widget. For example, if you were building a form where users select their preferred day of the week for scheduling appointments, a label could be used to give additional information about days and time an office is open (e.g., \"We are only open on Mondays and Tuesdays\"). I will use the <code>&#x3C;span></code> element for this (<code>tags$span</code>).</li>\n<li>Toggle: The listbox widget requires a <code>&#x3C;button></code> that opens and closes the widget. The text inside the button will be used to display the current value. I will also add an SVG icon to indicate that the button can be clicked and that there is expandable content.</li>\n<li>List of options: For the <code>&#x3C;select></code> elements, options are created using the <code>&#x3C;option></code> element, but this is not available for listboxes. Instead, I will use an unordered list (<code>&#x3C;ul></code>; <code>tags$ul</code>) and each option is created using a list item (<code>&#x3C;li></code>; <code>tags$li</code>) with the attribute <code>role = \"option\"</code>.</li>\n</ul>\n<p>Using the above list, here is the listbox HTML markup that we want the R functions to generate. I will talk about the required HTML- and ARIA attributes as we start writing the R functions.</p>\n<div class=\"gatsby-highlight\" data-language=\"html\"><pre class=\"language-html\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>fieldset</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>legend</span><span class=\"token punctuation\">></span></span>Title<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>legend</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>span</span><span class=\"token punctuation\">></span></span>A longer description<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>span</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>button</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>span</span><span class=\"token punctuation\">></span></span>Currently Selected Option<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>span</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>svg</span><span class=\"token punctuation\">></span></span>Icon<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>svg</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>button</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>ul</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span><span class=\"token punctuation\">></span></span>Option 1<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span><span class=\"token punctuation\">></span></span>Option 2<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span><span class=\"token punctuation\">></span></span>Option 3<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>li</span><span class=\"token punctuation\">></span></span>...<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>li</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>ul</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>fieldset</span><span class=\"token punctuation\">></span></span></code></pre></div>\n<p>How do we generate the HTML markup from R? Since there several HTML elements need to be created and linked with each other (via HTML attributes), and options need to be dynamically generated, I will create a primary function (or parent function) that calls several helper functions. The primary function will generate the IDs that link the child elements and pass this information for use in the helper functions. These helper functions are listed below.</p>\n<ol>\n<li><code>list_toggle</code>: I will create a function that renders the markup for the <code>&#x3C;button></code>. This includes the text element that will display the selected option and an SVG icon that visually indicates the button can be clicked.</li>\n<li><code>input_list_item</code>: Each option should be generated individually. This function generates a single list item that has an SVG icon (that will be visible when the option is selected) and an inner text label that displays the value of the option. Several attributes are also needed for good web accessibility practices and for communication between R and the JavaScript input binding (this will be discussed in a later section).</li>\n<li><code>input_list</code>: This helper function dynamically generates a list (<code>&#x3C;ul></code>) of options based on the number of input values (via the <code>input_list_item</code> function).</li>\n<li><code>listbox</code>: This the main function that will be used in your shiny app. This function runs the helper functions and generates the list of options. It also renders the title and description (if applicable).</li>\n</ol>\n<p>I will nest the helper functions (items 1 through 3) in list object.</p>\n<div class=\"gatsby-highlight\" data-language=\"r\"><pre class=\"language-r\"><code class=\"language-r\">helpers <span class=\"token operator\">&lt;-</span> list<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>The icons used in this package are available in <a href=\"https://github.com/davidruvolo51/rheroicons\">rheroicons</a> package. The rheroicons package is the R version of the <a href=\"https://github.com/tailwindlabs/heroicons\">heroicons</a> library.</p>\n<span id=\"work-r-listbox-toggle\" />\n<h4>Listbox toggle</h4>\n<p>The first helper function is the <code>list_toggle</code> function. This function generates the markup for the <code>&#x3C;button></code> that open and closes the list of options. Inside the button, the function will render a text label (that displays the current value) and an SVG icon (that visually indicates the button can be opened or closed). For good web accessibility practices, we will add the ARIA attributes <code>aria-haspopup</code>, <code>aria-expanded</code>, and <code>aria-labelledby</code>. I will also add a custom <code>data-*</code> attribute which may be useful selecting the button in CSS or JavaScript.</p>\n<div class=\"gatsby-highlight\" data-language=\"r\"><pre class=\"language-r\"><code class=\"language-r\">helpers<span class=\"token operator\">$</span>list_toggle <span class=\"token operator\">&lt;-</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span>inputId<span class=\"token punctuation\">,</span> titleId<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    buttonId <span class=\"token operator\">&lt;-</span> paste0<span class=\"token punctuation\">(</span>inputId<span class=\"token punctuation\">,</span> <span class=\"token string\">\"__\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"toggle\"</span><span class=\"token punctuation\">)</span>\n    buttonLabelId <span class=\"token operator\">&lt;-</span> paste0<span class=\"token punctuation\">(</span>buttonId<span class=\"token punctuation\">,</span> <span class=\"token string\">\"_label\"</span><span class=\"token punctuation\">)</span>\n\n    tags<span class=\"token operator\">$</span>button<span class=\"token punctuation\">(</span>\n        id <span class=\"token operator\">=</span> buttonId<span class=\"token punctuation\">,</span>\n        class <span class=\"token operator\">=</span> <span class=\"token string\">\"listbox-toggle\"</span><span class=\"token punctuation\">,</span>\n        `data<span class=\"token operator\">-</span>group` <span class=\"token operator\">=</span> inputId<span class=\"token punctuation\">,</span>\n        `aria<span class=\"token operator\">-</span>haspopup` <span class=\"token operator\">=</span> <span class=\"token string\">\"listbox\"</span><span class=\"token punctuation\">,</span>\n        `aria<span class=\"token operator\">-</span>expanded` <span class=\"token operator\">=</span> <span class=\"token string\">\"false\"</span><span class=\"token punctuation\">,</span>\n        `aria<span class=\"token operator\">-</span>labelledby` <span class=\"token operator\">=</span> paste0<span class=\"token punctuation\">(</span>titleId<span class=\"token punctuation\">,</span> <span class=\"token string\">\" \"</span><span class=\"token punctuation\">,</span> buttonLabelId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n\n        <span class=\"token comment\"># text element for current selected item</span>\n        tags<span class=\"token operator\">$</span>span<span class=\"token punctuation\">(</span>\n            id <span class=\"token operator\">=</span> buttonLabelId<span class=\"token punctuation\">,</span>\n            class <span class=\"token operator\">=</span> <span class=\"token string\">\"toggle-text\"</span>\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n\n        <span class=\"token comment\"># icon</span>\n        rheroicons<span class=\"token operator\">::</span>icons<span class=\"token operator\">$</span>chevron_down<span class=\"token punctuation\">(</span>\n            type <span class=\"token operator\">=</span> <span class=\"token string\">\"solid\"</span><span class=\"token punctuation\">,</span>\n            aria_hidden <span class=\"token operator\">=</span> <span class=\"token boolean\">TRUE</span><span class=\"token punctuation\">,</span>\n            class <span class=\"token operator\">=</span> <span class=\"token string\">\"toggle-icon\"</span>\n        <span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>The values for the arguments <code>inputId</code> and <code>titleId</code> are defined by the primary function. These values are used to link the legend and selected option label. The <code>aria-expanded</code> attribute informs users who use assistive web technologies if the list is visible or not (this attribute will be updated in the input binding).</p>\n<span id=\"work-r-listbox-options\" >\n<h4>Listbox options</h4>\n<p>Next, I will write the <code>input_list_item</code> function that generates each option. The returned element will have a label the displays the option and an SVG icon that will be visible when an option is selected. In addition, each option must have the attribute <code>role = \"option\"</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"r\"><pre class=\"language-r\"><code class=\"language-r\">helpers<span class=\"token operator\">$</span>input_list_item <span class=\"token operator\">&lt;-</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span>inputId<span class=\"token punctuation\">,</span> option<span class=\"token punctuation\">,</span> value<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    forId <span class=\"token operator\">&lt;-</span> paste0<span class=\"token punctuation\">(</span>inputId<span class=\"token punctuation\">,</span> <span class=\"token string\">\"__\"</span><span class=\"token punctuation\">,</span> option<span class=\"token punctuation\">)</span>\n\n    <span class=\"token comment\"># generate html</span>\n    tags<span class=\"token operator\">$</span>li<span class=\"token punctuation\">(</span>\n        id <span class=\"token operator\">=</span> forId<span class=\"token punctuation\">,</span>\n        class <span class=\"token operator\">=</span> <span class=\"token string\">\"listbox-option\"</span><span class=\"token punctuation\">,</span>\n        role <span class=\"token operator\">=</span> <span class=\"token string\">\"option\"</span><span class=\"token punctuation\">,</span>\n        `data<span class=\"token operator\">-</span>value` <span class=\"token operator\">=</span> value<span class=\"token punctuation\">,</span>\n        `data<span class=\"token operator\">-</span>group` <span class=\"token operator\">=</span> inputId<span class=\"token punctuation\">,</span>\n        `aria<span class=\"token operator\">-</span>labelledby` <span class=\"token operator\">=</span> forId<span class=\"token punctuation\">,</span>\n\n        <span class=\"token comment\"># selected icon</span>\n        rheroicons<span class=\"token operator\">::</span>icons<span class=\"token operator\">$</span>check_circle<span class=\"token punctuation\">(</span>\n            type <span class=\"token operator\">=</span> <span class=\"token string\">\"solid\"</span><span class=\"token punctuation\">,</span>\n            aria_hidden <span class=\"token operator\">=</span> <span class=\"token boolean\">TRUE</span><span class=\"token punctuation\">,</span>\n            class <span class=\"token operator\">=</span> <span class=\"token string\">\"option-icon\"</span>\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        <span class=\"token comment\"># label</span>\n        tags<span class=\"token operator\">$</span>span<span class=\"token punctuation\">(</span>\n            id <span class=\"token operator\">=</span> paste0<span class=\"token punctuation\">(</span>forId<span class=\"token punctuation\">,</span> <span class=\"token string\">\"-input-label\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            class <span class=\"token operator\">=</span> <span class=\"token string\">\"option-text\"</span><span class=\"token punctuation\">,</span>\n            option\n        <span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>The values for the arguments <code>inputId</code>, <code>option</code>, and <code>value</code> are passed down via the <code>input_list</code> function. I have also added a few custom data attributes that will be useful for selecting elements in CSS or the input binding.</p>\n<span id=\"work-r-listbox-list\" />\n<h4>Listbox list</h4>\n<p>The <code>input_list_item</code> function can then create be used in the <code>input_list</code> function to dynamically generate options. The returned element is an unordered list (<code>&#x3C;ul></code>). This element must have the attribute <code>role = \"listbox\"</code> and the attribute <code>tabindex = \"0\"</code> (as it will make the element focusable via the input binding). The ARIA attribute <code>aria-labelledby</code> is used to link the label and the list of options.</p>\n<div class=\"gatsby-highlight\" data-language=\"r\"><pre class=\"language-r\"><code class=\"language-r\">helpers<span class=\"token operator\">$</span>input_list <span class=\"token operator\">&lt;-</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span>inputId<span class=\"token punctuation\">,</span> titleId<span class=\"token punctuation\">,</span> data<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\n    <span class=\"token comment\"># generate markup for parent element</span>\n    parent <span class=\"token operator\">&lt;-</span> tags<span class=\"token operator\">$</span>ul<span class=\"token punctuation\">(</span>\n        id <span class=\"token operator\">=</span> paste0<span class=\"token punctuation\">(</span>inputId<span class=\"token punctuation\">,</span> <span class=\"token string\">\"__input_list\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        class <span class=\"token operator\">=</span> <span class=\"token string\">\"listbox-list hidden\"</span><span class=\"token punctuation\">,</span>\n        `data<span class=\"token operator\">-</span>group` <span class=\"token operator\">=</span> inputId<span class=\"token punctuation\">,</span>\n        `aria<span class=\"token operator\">-</span>labelledby` <span class=\"token operator\">=</span> titleId<span class=\"token punctuation\">,</span>\n        role <span class=\"token operator\">=</span> <span class=\"token string\">\"listbox\"</span><span class=\"token punctuation\">,</span>\n        tabindex <span class=\"token operator\">=</span> <span class=\"token string\">\"-1\"</span>\n    <span class=\"token punctuation\">)</span>\n\n    <span class=\"token comment\"># generate markup for child (&lt;li>) elements</span>\n    children <span class=\"token operator\">&lt;-</span> lapply<span class=\"token punctuation\">(</span>seq_len<span class=\"token punctuation\">(</span>length<span class=\"token punctuation\">(</span>data<span class=\"token operator\">$</span>options<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span>i<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        helpers<span class=\"token operator\">$</span>input_list_item<span class=\"token punctuation\">(</span>\n            inputId <span class=\"token operator\">=</span> inputId<span class=\"token punctuation\">,</span>\n            option <span class=\"token operator\">=</span> data<span class=\"token operator\">$</span>options<span class=\"token punctuation\">[</span><span class=\"token punctuation\">[</span>i<span class=\"token punctuation\">]</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n            value <span class=\"token operator\">=</span> data<span class=\"token operator\">$</span>values<span class=\"token punctuation\">[</span><span class=\"token punctuation\">[</span>i<span class=\"token punctuation\">]</span><span class=\"token punctuation\">]</span>\n        <span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n    <span class=\"token comment\"># bind to parent (you can add blank option here)</span>\n    parent<span class=\"token operator\">$</span>children <span class=\"token operator\">&lt;-</span> children\n\n    <span class=\"token comment\"># return</span>\n    return<span class=\"token punctuation\">(</span>parent<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Input values for the <code>input_list</code> function are passed down from the main <code>listbox</code> function.</p>\n<span id=\"work-r-listbox\" />\n<h4>Main listbox function</h4>\n<p>Now that the helper functions are defined, we can use them in the main function. To align the function with other Shiny input elements, I will use the following arguments.</p>\n<div class=\"gatsby-highlight\" data-language=\"r\"><pre class=\"language-r\"><code class=\"language-r\">listbox<span class=\"token punctuation\">(</span>inputId<span class=\"token punctuation\">,</span> title<span class=\"token punctuation\">,</span> label <span class=\"token operator\">=</span> <span class=\"token keyword\">NULL</span><span class=\"token punctuation\">,</span> options<span class=\"token punctuation\">,</span> values <span class=\"token operator\">=</span> <span class=\"token keyword\">NULL</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>By default, the <code>label</code> and <code>values</code> arguments are optional. If <code>values</code> is missing, then the input for <code>options</code> is used. Inputs for <code>options</code> and <code>values</code> should be a character array (i.e., <code>options = c(...)</code>).</p>\n<div class=\"gatsby-highlight\" data-language=\"r\"><pre class=\"language-r\"><code class=\"language-r\">listbox <span class=\"token operator\">&lt;-</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span>inputId<span class=\"token punctuation\">,</span> title<span class=\"token punctuation\">,</span> label <span class=\"token operator\">=</span> <span class=\"token keyword\">NULL</span><span class=\"token punctuation\">,</span> options<span class=\"token punctuation\">,</span> values <span class=\"token operator\">=</span> <span class=\"token keyword\">NULL</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\n    <span class=\"token comment\"># validate</span>\n    stopifnot<span class=\"token punctuation\">(</span>is.character<span class=\"token punctuation\">(</span>inputId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    stopifnot<span class=\"token punctuation\">(</span>is.character<span class=\"token punctuation\">(</span>title<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    stopifnot<span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>is.null<span class=\"token punctuation\">(</span>options<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\n    <span class=\"token comment\"># process options + values</span>\n    data <span class=\"token operator\">&lt;-</span> list<span class=\"token punctuation\">(</span>options <span class=\"token operator\">=</span> options<span class=\"token punctuation\">,</span> values <span class=\"token operator\">=</span> options<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>is.null<span class=\"token punctuation\">(</span>values<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> data<span class=\"token operator\">$</span>values <span class=\"token operator\">&lt;-</span> values\n\n    <span class=\"token comment\"># set ID of text elements (for aria attributes)</span>\n    titleId <span class=\"token operator\">&lt;-</span> paste0<span class=\"token punctuation\">(</span>inputId<span class=\"token punctuation\">,</span> <span class=\"token string\">\"__title\"</span><span class=\"token punctuation\">)</span>\n    labelId <span class=\"token operator\">&lt;-</span> paste0<span class=\"token punctuation\">(</span>inputId<span class=\"token punctuation\">,</span> <span class=\"token string\">\"__label\"</span><span class=\"token punctuation\">)</span>\n\n    <span class=\"token comment\"># build component</span>\n    el <span class=\"token operator\">&lt;-</span> tags<span class=\"token operator\">$</span>fieldset<span class=\"token punctuation\">(</span>\n        id <span class=\"token operator\">=</span> inputId<span class=\"token punctuation\">,</span>\n        class <span class=\"token operator\">=</span> <span class=\"token string\">\"listbox-group hidden\"</span><span class=\"token punctuation\">,</span>\n        `data<span class=\"token operator\">-</span>group` <span class=\"token operator\">=</span> inputId<span class=\"token punctuation\">,</span>\n        `data<span class=\"token operator\">-</span>value` <span class=\"token operator\">=</span> <span class=\"token string\">\"NULL\"</span><span class=\"token punctuation\">,</span>\n\n        <span class=\"token comment\"># define title for the input group</span>\n        tags<span class=\"token operator\">$</span>legend<span class=\"token punctuation\">(</span>\n            id <span class=\"token operator\">=</span> titleId<span class=\"token punctuation\">,</span>\n            class <span class=\"token operator\">=</span> <span class=\"token string\">\"listbox-title\"</span><span class=\"token punctuation\">,</span>\n            title\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n\n        <span class=\"token comment\"># generate menu toggle</span>\n        helpers<span class=\"token operator\">$</span>list_toggle<span class=\"token punctuation\">(</span>\n            inputId <span class=\"token operator\">=</span> inputId<span class=\"token punctuation\">,</span>\n            titleId <span class=\"token operator\">=</span> titleId\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n\n        <span class=\"token comment\"># generate options list</span>\n        helpers<span class=\"token operator\">$</span>input_list<span class=\"token punctuation\">(</span>\n            inputId <span class=\"token operator\">=</span> inputId<span class=\"token punctuation\">,</span>\n            data <span class=\"token operator\">=</span> data<span class=\"token punctuation\">,</span>\n            titleId <span class=\"token operator\">=</span> titleId\n        <span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">)</span>\n\n    <span class=\"token comment\"># append label if present</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>is.null<span class=\"token punctuation\">(</span>label<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        stopifnot<span class=\"token punctuation\">(</span>is.character<span class=\"token punctuation\">(</span>label<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n        el<span class=\"token operator\">$</span>children <span class=\"token operator\">&lt;-</span> tagList<span class=\"token punctuation\">(</span>\n            el<span class=\"token operator\">$</span>children<span class=\"token punctuation\">[</span><span class=\"token number\">1</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n            tags<span class=\"token operator\">$</span>span<span class=\"token punctuation\">(</span>\n                id <span class=\"token operator\">=</span> labelId<span class=\"token punctuation\">,</span>\n                class <span class=\"token operator\">=</span> <span class=\"token string\">\"listbox-label\"</span><span class=\"token punctuation\">,</span>\n                lab\n            <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            el<span class=\"token operator\">$</span>children<span class=\"token punctuation\">[</span><span class=\"token number\">2</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n            el<span class=\"token operator\">$</span>children<span class=\"token punctuation\">[</span><span class=\"token number\">3</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n        <span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token comment\"># return</span>\n    return<span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>The label for the listbox widget is added only if a string is supplied. If present, the label is inserted after the title and before the button.</p>\n<p>That is it for the R function. Load the CSS file into your app or add it to your existing CSS file. If you were to run the app at this point, it would return a simple button that does nothing when it is clicked. In the next section, we will create a custom input binding to define the behavior of the listbox widget.</p>\n<span id=\"work-js\" />\n<h3>Creating the JavaScript input binding</h3>\n<p>In this section, we will be working in <code>www/js/listbox.js</code>.</p>\n<p>Shiny input bindings consist of a series of methods that define what happens when the listbox widget is rendered, when the user clicks the button or presses the down arrow key. There are several methods available (by Shiny.js) and are further detailed in RStudio's <a href=\"https://shiny.rstudio.com/articles/js-custom-input.html\">Shiny input bindings guide</a>. The listbox widget will use the <code>initialize</code> (at render), <code>getValue</code> (how to set the value of widget), and <code>subscribe</code> (the events; buttons, key presses, etc.) methods. </p>\n<p>The basic structure of the listbox input binding is in the following code block. New input bindings are created using <code>new Shiny.InputBinding()</code>. Use jQuery's <code>extend</code> to define the methods specific to the component (i.e., events, values to return, receive messages from R, etc.). Bindings must be registered with Shiny using <code>Shiny.inputBindings.register(...)</code>. Here is the basic structure for the listbox widget. I have already written the <code>find</code> and <code>unsubscribe</code> methods. <code>find</code> returns all instances of the listbox widget using the CSS class name (<code>listbox-group</code>; defined by the <code>listbox</code> function) and <code>unsubcribe</code> removes events created by the <code>subscribe</code> method.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// init binding</span>\n<span class=\"token keyword\">var</span> listbox <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Shiny<span class=\"token punctuation\">.</span>InputBinding</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n\n<span class=\"token comment\">// define methods</span>\n$<span class=\"token punctuation\">.</span><span class=\"token function\">extend</span><span class=\"token punctuation\">(</span>listbox<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n\n    <span class=\"token comment\">// find: locate all instances of the listbox widget</span>\n    <span class=\"token function-variable function\">find</span><span class=\"token operator\">:</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">scope</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">return</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>scope<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\".listbox-group\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n\n    <span class=\"token comment\">// on render</span>\n    <span class=\"token function-variable function\">initialize</span><span class=\"token operator\">:</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">el</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n\n    <span class=\"token comment\">// returns the value of the listbox to be accessed in R via input$...</span>\n    <span class=\"token function-variable function\">getValue</span><span class=\"token operator\">:</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">el</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n\n    <span class=\"token comment\">// events</span>\n    <span class=\"token function-variable function\">subscribe</span><span class=\"token operator\">:</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">el<span class=\"token punctuation\">,</span> callback</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n\n    <span class=\"token comment\">// off: remove events defined in subscribe</span>\n    <span class=\"token function-variable function\">unsubscribe</span><span class=\"token operator\">:</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">el</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">off</span><span class=\"token punctuation\">(</span><span class=\"token string\">\".listbox\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// register binding</span>\nShiny<span class=\"token punctuation\">.</span>inputBindings<span class=\"token punctuation\">.</span><span class=\"token function\">register</span><span class=\"token punctuation\">(</span>listbox<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<span id=\"work-js-initialize\" />\n<h4>initialize</h4>\n<p>The purpose of the initialize method is to define what happens to the listbox widget as soon as it is rendered. By default, the widget sets the first option as the starting value. The value of the first option will be used to update the text display of the widget and made available in the Shiny server (via <code>input$...</code>). In this example, I set the value of the selected option to the custom data attribute <code>data-value</code> (found in the <code>&#x3C;fieldset></code> element). This step is not really relevant, but it could be useful if you would like to customize the appearance of the widget based on its current value.</p>\n<p>There are also a few ARIA attributes that need to be set in this step. First, the list element (i.e., <code>&#x3C;ul></code>) needs to have the property <code>aria-activedescendant</code>. This attribute is updated when a new option is selected and the value is always the ID of the selected option. Second, the first option — and any selected option — must have the <code>aria-selected</code> attribute added. When this property is used, the value must be set to <code>true</code>. Remove this attribute entirely when an option is deselected rather than using <code>false</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">$<span class=\"token punctuation\">.</span><span class=\"token function\">extend</span><span class=\"token punctuation\">(</span>listbox<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// ...</span>\n\n    <span class=\"token function-variable function\">initialize</span><span class=\"token operator\">:</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">el</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\n        <span class=\"token comment\">// select list (ul) and first item in the list (li)</span>\n        <span class=\"token keyword\">var</span> list <span class=\"token operator\">=</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"ul[role='listbox']\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">var</span> first <span class=\"token operator\">=</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"li[role='option']\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">first</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token comment\">// update ARIA attributes</span>\n        list<span class=\"token punctuation\">.</span><span class=\"token function\">attr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-activedescendant\"</span><span class=\"token punctuation\">,</span> first<span class=\"token punctuation\">.</span><span class=\"token function\">attr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"id\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n        first<span class=\"token punctuation\">.</span><span class=\"token function\">attr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-selected\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"true\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token comment\">// add the value of the first item to the parent container (i.e., &lt;fieldset>)</span>\n        <span class=\"token comment\">// to a custom data attribute</span>\n        <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">attr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"data-value\"</span><span class=\"token punctuation\">,</span> first<span class=\"token punctuation\">.</span><span class=\"token function\">attr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"id\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token comment\">// update displayed text</span>\n        <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\".toggle-text\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">text</span><span class=\"token punctuation\">(</span>first<span class=\"token punctuation\">.</span><span class=\"token function\">attr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"data-value\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n\n    <span class=\"token comment\">/// ...</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<span id=\"work-js-getValue\" />\n<h4>getValue</h4>\n<p>The <code>getValue</code> method will return the value of select option and make it available in the Shiny server. This method finds the option with the ARIA attribute <code>aria-selected</code> and extract its value.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">$<span class=\"token punctuation\">.</span><span class=\"token function\">extend</span><span class=\"token punctuation\">(</span>listbox<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// ...</span>\n\n    <span class=\"token function-variable function\">getValue</span><span class=\"token operator\">:</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">el</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">return</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"li[aria-selected='true']\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">attr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"data-value\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n\n    <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<span id=\"work-js-subscribe\" />\n<h4>subscribe</h4>\n<p>The subscribe method is used to define the behaviors of the listbox component in response to an event (e.g., mouse clicks, key presses, etc.). To ensure good web accessibility practices, the listbox widget must respond to several keyboard events. In The Web Accessibility Initiative (WAI) Authoring Practices <a href=\"https://www.w3.org/TR/wai-aria-practices/examples/listbox/listbox-collapsible.html\">collapsible listbox widget</a> example, it is recommended to use the following events: enter, escape, up and down arrow, home, and end. These keys will handle the opening and closing of the listbox, navigation within the list of options, and the selection of new items. Since we need to attach these behaviors based on mouse and keyboard clicks, I will write a few helper functions that will open, close, and toggle the list of options, as well as a function that updates the component when a new option is selected.</p>\n<p>The open and close functions are fairly straightforward. These functions either add or remove the CSS class <code>hidden</code> from the list, which toggles the CSS property <code>display: none</code>. Both functions will also update the ARIA attribute <code>aria-expanded</code> assigned to the listbox button. For visual purposes, the CSS class <code>rotated</code> will be added to the SVG icon. This will rotate the toggle icon (downward pointing chevron) by 180 degrees. The <code>closeMenu</code> and <code>openMenu</code> functions are wrapped in the <code>toggleMenu</code> function.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// define function that closes menu</span>\n<span class=\"token keyword\">function</span> <span class=\"token function\">closeMenu</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\n    <span class=\"token comment\">// find elements that will be modified on close</span>\n    <span class=\"token keyword\">var</span> menu <span class=\"token operator\">=</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"ul[role='listbox']\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">var</span> toggle <span class=\"token operator\">=</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"button.listbox-toggle\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token comment\">// modify attributes</span>\n    menu<span class=\"token punctuation\">.</span><span class=\"token function\">addClass</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"hidden\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    toggle<span class=\"token punctuation\">.</span><span class=\"token function\">attr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-expanded\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"false\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    toggle<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\".toggle-icon\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">removeClass</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"rotated\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// define function that opens menu</span>\n<span class=\"token keyword\">function</span> <span class=\"token function\">openMenu</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\n    <span class=\"token comment\">// find elements that will be modified on open</span>\n    <span class=\"token keyword\">var</span> menu <span class=\"token operator\">=</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"ul[role='listbox']\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">var</span> toggle <span class=\"token operator\">=</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"button.listbox-toggle\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token comment\">// modify attributes</span>\n    menu<span class=\"token punctuation\">.</span><span class=\"token function\">removeClass</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"hidden\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    toggle<span class=\"token punctuation\">.</span><span class=\"token function\">attr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-expanded\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"false\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    toggle<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\".toggle-icon\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">addClass</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"rotated\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token comment\">// focus menu and scroll to selected element</span>\n    menu<span class=\"token punctuation\">.</span><span class=\"token function\">focus</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// define function that toggles menu state</span>\n<span class=\"token keyword\">function</span> <span class=\"token function\">toggleMenu</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">var</span> menu <span class=\"token operator\">=</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"ul[role='listbox']\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>menu<span class=\"token punctuation\">.</span><span class=\"token function\">hasClass</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"hidden\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token function\">openMenu</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token function\">closeMenu</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Next, we will need a function that updates the value of the listbox widget whenever an option is selected. This function will update the <code>aria-selected</code> attribute of the new option and update the displayed text with the new value. The function will also extract the ID of the new option and update the attribute <code>aria-activedescendant</code> assigned to the unordered list element. The last step runs a callback function — which is the <code>getValue</code> method — to update the value in the Shiny server.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// update component and selected item</span>\n<span class=\"token keyword\">function</span> <span class=\"token function\">updateInput</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">elem</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// focus new element</span>\n    <span class=\"token keyword\">var</span> newElem <span class=\"token operator\">=</span> elem<span class=\"token punctuation\">;</span>\n    newElem<span class=\"token punctuation\">.</span><span class=\"token function\">attr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-selected\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"true\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    newElem<span class=\"token punctuation\">.</span><span class=\"token function\">addClass</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"focus\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token comment\">// update menu attribute</span>\n    <span class=\"token keyword\">var</span> menu <span class=\"token operator\">=</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"ul[role='listbox']\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    menu<span class=\"token punctuation\">.</span><span class=\"token function\">attr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-activedescendant\"</span><span class=\"token punctuation\">,</span> elem<span class=\"token punctuation\">.</span><span class=\"token function\">attr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"id\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token comment\">// update component value + display text</span>\n    <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">attr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"data-value\"</span><span class=\"token punctuation\">,</span> elem<span class=\"token punctuation\">.</span><span class=\"token function\">attr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"data-value\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\".toggle-text\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">text</span><span class=\"token punctuation\">(</span>elem<span class=\"token punctuation\">.</span><span class=\"token function\">attr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"data-value\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token comment\">// run callback (i.e., getValue)</span>\n    <span class=\"token function\">callback</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Using these functions, we can define the events for the listbox widget. There are three events: what happens when the button is clicked, when an option is clicked, and when a key is pressed. The first event, is attached to the listbox button and it will either open or close the listbox via <code>toggleMenu</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// event: when menu toggle is clicked</span>\n<span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">on</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"click\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"button.listbox-toggle\"</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">toggleMenu</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>The <code>keydown</code> event is a bit more involved than the click event as each key will results in a different action. Key codes can be accessed through <code>keyCode</code> data available from event (<code>e</code> for short) interface. The keys that are used in this binding are listed in the following table.</p>\n<table>\n<thead>\n<tr>\n<th align=\"left\">key</th>\n<th align=\"left\">behavior</th>\n<th align=\"left\">code</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td align=\"left\">up arrow</td>\n<td align=\"left\">focus previous option</td>\n<td align=\"left\">38</td>\n</tr>\n<tr>\n<td align=\"left\">down arrow</td>\n<td align=\"left\">focus next option</td>\n<td align=\"left\">40</td>\n</tr>\n<tr>\n<td align=\"left\">home</td>\n<td align=\"left\">focus first option</td>\n<td align=\"left\">36</td>\n</tr>\n<tr>\n<td align=\"left\">end</td>\n<td align=\"left\">focus last option</td>\n<td align=\"left\">35</td>\n</tr>\n<tr>\n<td align=\"left\">escape</td>\n<td align=\"left\">close menu</td>\n<td align=\"left\">27</td>\n</tr>\n<tr>\n<td align=\"left\">enter</td>\n<td align=\"left\">select current option</td>\n<td align=\"left\">13</td>\n</tr>\n</tbody>\n</table>\n<p>All key presses — except escape — will update the listbox's value automatically.</p>\n<p>I will use switch statement to define the action for each key. The escape key is the simplest case as it closes the listbox (i.e., runs <code>closeMenu()</code>). When the enter key is pressed, the listbox is closed and the current option is selected. Behaviors for the up arrow, down arrow, home, and end are similar to enter, but these actions use jQuery's <code>prev</code>, <code>next</code>, <code>first</code> or <code>last</code> functions —along with <code>length</code>— to determine if there are any sibling elements. For example, if the first option is focused and the down arrow key is pressed, then the second option is selected. If the last option is focused and the down arrow is pressed, then nothing happens as there are no more options to select. </p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// event: watch for keydowns</span>\n<span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">on</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"keydown\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"ul[role='listbox']\"</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">switch</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span>keyCode<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\n        <span class=\"token comment\">// on keydown: ArrowUp - code 38</span>\n        <span class=\"token keyword\">case</span> <span class=\"token number\">38</span><span class=\"token operator\">:</span>\n            <span class=\"token keyword\">var</span> current <span class=\"token operator\">=</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"li[aria-selected='true']\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>current<span class=\"token punctuation\">.</span><span class=\"token function\">prev</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>length<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                <span class=\"token keyword\">var</span> newElem <span class=\"token operator\">=</span> current<span class=\"token punctuation\">.</span><span class=\"token function\">prev</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n                current<span class=\"token punctuation\">.</span><span class=\"token function\">removeAttr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-selected\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n                <span class=\"token function\">updateInput</span><span class=\"token punctuation\">(</span>newElem<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token punctuation\">}</span>\n            <span class=\"token keyword\">break</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token comment\">// on keydown: ArrowDown - code 40</span>\n        <span class=\"token keyword\">case</span> <span class=\"token number\">40</span><span class=\"token operator\">:</span>\n            <span class=\"token keyword\">var</span> current <span class=\"token operator\">=</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"li[aria-selected='true']\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>current<span class=\"token punctuation\">.</span><span class=\"token function\">next</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>length<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                <span class=\"token keyword\">var</span> newElem <span class=\"token operator\">=</span> current<span class=\"token punctuation\">.</span><span class=\"token function\">next</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n                current<span class=\"token punctuation\">.</span><span class=\"token function\">removeAttr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-selected\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n                <span class=\"token function\">updateInput</span><span class=\"token punctuation\">(</span>newElem<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token punctuation\">}</span>\n            <span class=\"token keyword\">break</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token comment\">// on keydown: Home - code 36</span>\n        <span class=\"token keyword\">case</span> <span class=\"token number\">36</span><span class=\"token operator\">:</span>\n            <span class=\"token keyword\">var</span> current <span class=\"token operator\">=</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"li[aria-selected='true']\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token keyword\">var</span> first <span class=\"token operator\">=</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"li[role='option']\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">first</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            current<span class=\"token punctuation\">.</span><span class=\"token function\">removeAttr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-selected\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token function\">updateInput</span><span class=\"token punctuation\">(</span>first<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token keyword\">break</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token comment\">// on keydown: End - code 35</span>\n        <span class=\"token keyword\">case</span> <span class=\"token number\">35</span><span class=\"token operator\">:</span>\n            <span class=\"token keyword\">var</span> current <span class=\"token operator\">=</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"li[aria-selected='true']\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token keyword\">var</span> last <span class=\"token operator\">=</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"li[role='option']\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">last</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            current<span class=\"token punctuation\">.</span><span class=\"token function\">removeAttr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-selected\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token function\">updateInput</span><span class=\"token punctuation\">(</span>last<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token keyword\">break</span><span class=\"token punctuation\">;</span>\n        \n        <span class=\"token comment\">// on keydown: Escape - code 27</span>\n        <span class=\"token keyword\">case</span> <span class=\"token number\">27</span><span class=\"token operator\">:</span>\n            <span class=\"token function\">closeMenu</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token keyword\">break</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token comment\">// on keydown: Enter - code 13</span>\n        <span class=\"token keyword\">case</span> <span class=\"token number\">13</span><span class=\"token operator\">:</span>\n            <span class=\"token keyword\">var</span> selected <span class=\"token operator\">=</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token function\">updateInput</span><span class=\"token punctuation\">(</span>selected<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token function\">closeMenu</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token keyword\">break</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>The last event is a click event that will be attached to each list item. This event will update the component using the value of the clicked item. Like the previous events, the ARIA attribute of the previously select option will be removed.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// on event: when option clicked</span>\n<span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">on</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"click\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"li[role='option']\"</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\n    <span class=\"token comment\">// make sure the &lt;li> element is selected</span>\n    <span class=\"token comment\">// this will handle situations when &lt;span> or &lt;icon> is</span>\n    <span class=\"token comment\">// clicked</span>\n    <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"li[role='option'][aria-selected='true']\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">removeAttr</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"aria-selected\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">var</span> elem <span class=\"token operator\">=</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">closest</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"li[role='option']\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">updateInput</span><span class=\"token punctuation\">(</span>elem<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">closeMenu</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>JQuery's <code>closest()</code> function is used to ignore the child elements (text and SVG icon) inside the selection option and return the list item.</p>\n<p>The full input binding can be found on GitHub in the file <a href=\"https://github.com/davidruvolo51/shinyAppTutorials/blob/prod/shiny-listbox/www/js/listbox.js\">listbox.js</a></p>\n<span id=\"know\" />\n<h2>What do I need to know before I integrate this into my app?</h2>\n<p>At the moment, the listbox component is fairly basic and the functionality of the widget could be improved. Initial accessibility checks were run using the <a href=\"https://wave.webaim.org\">Web Accessibility Evaluation Tool (WAVE)</a>, but I would recommend further testing and review before using the listbox widget in any production application. </p>\n<p>The code discussed in this post, provide a starting point for creating the listbox component. The functionality is fairly limited as only one option can be selected at a time. It is possible to add a multiple selection feature, but more key press events are required. It is likely that other input elements (checkbox groups, radio groups, etc.) are better options as some behaviors created for the listbox widget are already browser-ready. Semantic HTML elements are always better than custom components. Expanding this example to include multiple selections would take more thought and planning, and I wanted to keep this post relatively simple. </p>\n<p>The listbox widget will also be included in <a href=\"https://github.com/davidruvolo51/accessibleshiny\">accessibleshiny</a> package, so keep an eye out for a new version!</p>\n<span id=\"run\" />\n<h2>How do I run the example?</h2>\n<p>The full code for the demo is available on GitHub in the <a href=\"https://github.com/davidruvolo51/shinyAppTutorials/tree/prod/shiny-listbox\">Listbox subfolder</a>. Alternatively, you can run the app directly from the R console using the following command.</p>\n<div class=\"gatsby-highlight\" data-language=\"r\"><pre class=\"language-r\"><code class=\"language-r\">shiny<span class=\"token operator\">::</span>runGitHub<span class=\"token punctuation\">(</span>\n    repo <span class=\"token operator\">=</span> <span class=\"token string\">\"shinyAppTutorials\"</span><span class=\"token punctuation\">,</span>\n    username <span class=\"token operator\">=</span> <span class=\"token string\">\"davidruvolo51\"</span><span class=\"token punctuation\">,</span>\n    subdir <span class=\"token operator\">=</span> <span class=\"token string\">\"shiny-listbox\"</span>\n<span class=\"token punctuation\">)</span></code></pre></div>\n<span id=\"further-reading\" />\n<h2>Further reading</h2>\n<p>For more information about the concepts and resources mentioned in this post, please visit the following links.</p>\n<ul>\n<li>Mozilla's <a href=\"https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/listbox_role\">listbox role reference</a></li>\n<li>On Key event codes: <a href=\"https://keycode.info\">keycode.info</a></li>\n<li>RStudio's <a href=\"https://shiny.rstudio.com/articles/building-inputs.html\">Building Inputs Guide</a></li>\n<li>RStudio's <a href=\"https://shiny.rstudio.com/articles/js-custom-input.html\">How to create custom input bindings</a></li>\n<li><a href=\"https://www.w3.org/TR/wai-aria-practices/\">WAI-ARIA Authoring Practices</a></li>\n<li>WAI-ARIA's <a href=\"https://www.w3.org/TR/wai-aria-practices/#Listbox\">Listbox Widget</a></li>\n<li>WAI-ARIA's <a href=\"https://www.w3.org/TR/wai-aria-practices/examples/listbox/listbox-collapsible.html\">Collapsible Dropdown Listbox Example</a></li>\n<li><a href=\"https://wave.webaim.org\">Web Accessibility Evaluation Tool (WAVE)</a></li>\n</ul>","frontmatter":{"title":"Listbox Widget","subtitle":"Creating a customizable dropdown menu component for Shiny","abstract":"Select inputs are commonly used in Shiny for creating dropdown menus. Select inputs are easy to use, but they are not easy to style using CSS. An alternative solution is the listbox widget.","date":"2020-09-03","updated":"2020-09-03","keywords":["html","javascript"]},"fields":{"readingTime":{"minutes":19.625}}}},"pageContext":{"slug":"/tutorials/listbox-widget/"}},"staticQueryHashes":["63159454"]}