Search Bar (Single Selection)
Incase you want user not to select more than one value. It is to prevent multiple selection from dropdown. You can use multiple = FALSE
for selection of single item. Option maxItems = '1'
removes dropdown icon which is by default shown in the dropdown. To make selectizeInput
behave like a search bar, we have used javascript mentioned in onDropdownOpen
and onType
options.
In the choices
argument we have used concatenation of two random letters of alphabet. For example `AB`. Since it is random, it's not necessary `AB` exists in the dropdown :-( You can remove the selected value via backspace.
library(shiny) ui <- fluidPage( title = "Search Bar", fluidRow( selectizeInput( inputId = "searchme", label = "Search Bar", multiple = FALSE, choices = c("Search Bar" = "", paste0(LETTERS,sample(LETTERS, 26))), options = list( create = FALSE, placeholder = "Search Me", maxItems = '1', onDropdownOpen = I("function($dropdown) {if (!this.lastQuery.length) {this.close(); this.settings.openOnFocus = false;}}"), onType = I("function (str) {if (str === \"\") {this.close();}}") ) )) ) server <- function(input, output, session) { # Show Selected Value in Console observe({ print(input$searchme) }) } shinyApp(ui, server)
Search Bar (Multiple Selection)
In this section we are showing how to select more than one value from dropdown. To make multiple section working, you need to set multiple = TRUE
along with the javascript mentioned in onItemAdd
option.
library(shiny) ui <- fluidPage( title = "Search Bar", fluidRow( selectizeInput( inputId = "searchme", label = "Search Bar", multiple = TRUE, choices = paste0(LETTERS,sample(LETTERS, 26)), options = list( create = FALSE, placeholder = "Search Me", onDropdownOpen = I("function($dropdown) {if (!this.lastQuery.length) {this.close(); this.settings.openOnFocus = false;}}"), onType = I("function (str) {if (str === \"\") {this.close();}}"), onItemAdd = I("function() {this.close();}") ) )) ) server <- function(input, output, session) { # Show Selected Value in Console observe({ print(input$searchme) }) } shinyApp(ui, server)
Add icon in Search Bar
If you want to add search icon to improve appearence of the search box, you can accomplish it via CSS styling. We are using Glyphicons icons which comes with bootstrap so you don't need to add additional library for icons.
library(shiny) ui <- fluidPage( title = "Search Bar", fluidRow( tags$style(HTML(" .selectize-input.items.not-full.has-options:before { content: '\\e003'; font-family: \"Glyphicons Halflings\"; line-height: 2; display: block; position: absolute; top: 0; left: 0; padding: 0 4px; font-weight:900; } .selectize-input.items.not-full.has-options { padding-left: 24px; } .selectize-input.items.not-full.has-options.has-items { padding-left: 0px; } .selectize-input.items.not-full.has-options .item:first-child { margin-left: 20px; } ")), selectizeInput( inputId = "searchme", label = "Search Bar", multiple = T, choices = c("SBI Cap", "SBI Technology", "Kotak Technology"), options = list( create = FALSE, placeholder = "Search Me", onDropdownOpen = I("function($dropdown) {if (!this.lastQuery.length) {this.close(); this.settings.openOnFocus = false;}}"), onType = I("function (str) {if (str === \"\") {this.close();}}"), onItemAdd = I("function() {this.close();}") ) )) ) server <- function(input, output, session) { # Show Selected Value in Console observe({ print(input$searchme) }) } shinyApp(ui, server)
Add image in Search Bar
To add custom image, you can change CSS from the previous section to the CSS shown below.
.selectize-input.items.not-full.has-options:before { content:''; background: url('https://cdn.iconscout.com/icon/free/png-256/google-1772223-1507807.png'); /*url of image*/ height: 16px; /*height of image*/ width: 16px; /*width of image*/ position: absolute; display: block; position: absolute; left: 0; background-size: 16px 16px; background-repeat: no-repeat; margin-left: 3px; } .selectize-input.dropdown-active:before { top: 0; margin-top: 6px; } .selectize-input.items.not-full.has-options { padding-left: 24px; } .selectize-input.items.not-full.has-options.has-items { padding-left: 0px; } .selectize-input.items.not-full.has-options .item:first-child { margin-left: 20px; }
Search Bar using Shiny Widgets
shinyWidgets
is a great package for widgets implemented for shiny. It offers several controls for interactivity. It has searchInput()
widget for search bar but that does not allow suggestions as user enters text. We can customise pickerInput
widget but it has limitation of not allowing to remove text via backspace but it shows Clear Text
button on top of dropdown to clear selection.
This implementation is a bit messy as compared to above selectizeInput
. It requires changes via javascript and CSS. `live-search` = TRUE
allows live suggestion in dropdown box.
library(shiny) library(shinyWidgets) ui <- fluidPage( title = "Search Bar", fluidRow( tags$script(HTML( "var CONTROL_INTERVAL = setInterval(function(){ if($('#searchme').length > 0 ){ $('#searchme').on('show.bs.select', function(){ var input = $('.bootstrap-select:has(select[id=\"searchme\"]) .bs-searchbox > input'); var opts = $(this).parent().find('div[role=\"listbox\"] ul li'); var opts0 = $(this).parent().find('div[role=\"listbox\"]'); opts.hide(); opts0.hide(); input.on('input', function(e){ if ($(this).val() !== \"\") {opts.show(); opts0.show();} else {opts.hide(); opts0.hide();} }); }); clearInterval(CONTROL_INTERVAL); }}, 200); " )), tags$style(HTML(".bs-select-all {display: none;} .bs-deselect-all {width: 100% !important;}")), pickerInput( inputId = "searchme", label = "Search Bar", choices = paste0(LETTERS,sample(LETTERS, 26)), multiple = TRUE, options = pickerOptions(title = "Search Me", `live-search` = TRUE, actionsBox = TRUE, deselectAllText = "Clear Search") ) )) server <- function(input, output, session) { # Show Selected Value in Console observe({ print(input$searchme) }) } shinyApp(ui, server)
Search Bar with large option lists
selectize is slow when you have large number of values. In the example below we are using dqshiny
library which is very efficient.
library(shiny) library(dqshiny) # create 100K random words opts <- sapply(1:100000, function(i) paste0(sample(letters, 7), collapse="")) ui <- fluidPage( fontawesome::fa_html_dependency(), tags$style("input{font-family:'Font Awesome\ 5 Free';font-weight: 900;} input:placeholder-shown#auto2{ background-image: url('https://cdn.iconscout.com/icon/free/png-256/google-1772223-1507807.png'); text-indent: 20px; background-size: 16px 16px; background-repeat: no-repeat; background-position: 8px 8px; } input#auto2:focus{ background-image:none; text-indent: 0px;}"), fluidRow( column(3, autocomplete_input("auto1", "Unnamed:", opts, placeholder = " Search Value", max_options = 1000), autocomplete_input("auto2", "Named:", placeholder = "Search Value", max_options = 1000, structure(opts, names = opts[order(opts)])) ), column(3, tags$label("Value:"), verbatimTextOutput("val1", placeholder = TRUE), tags$label("Value:"), verbatimTextOutput("val2", placeholder = TRUE) ) ) ) server <- function(input, output) { output$val1 <- renderText(as.character(input$auto1)) output$val2 <- renderText(as.character(input$auto2)) } shinyApp(ui, server)
BEST COLLECTION OF CONTENT
ReplyDelete