Simple Input Validation With Bootstrap Validation API

2 min read

Bootstrap allows you to build forms with validation. But by default, it only works if inputs are collected in a <form> and the validation is triggered by clicking a button with type="submit". What if we want to continuously validate inputs as they change?

We can leverage how Bootstrap uses .is-invalid and .invalid-feedback classes to add validation feedback and show them on selected events. For a text input, we could use:

We can create a validate function that takes a component and adds the validation attributes to the input.

library(shiny)
library(bslib)

validate <- function(
  component,
  condition = "x => x === ''",
  invalid_label = "Name must be provided."
) {
  validation_js <- htmlwidgets::JS(sprintf("
    const condition = %s;
    if (condition(this.value)) {
      $(this)
        .addClass('is-invalid')
        .parent()
        .append('<div class=\"invalid-feedback\">%s</div>')
    } else {
      $(this).parent().find('.invalid-feedback').remove();
      $(this).removeClass('is-invalid');
    }",
    condition,
    invalid_label
  ))
  tagAppendAttributes(
    component,
    .cssSelector = "input",
    oninput = validation_js
  )
}

shinyApp(
  ui = fluidPage(
    theme = bs_theme(version = 5),
    textInput(
      inputId = "name",
      label = "Name",
      width = "100%"
    ) |>
      validate()
  ),
  server = function(input, output) {

  }
)

It’s super simple requires no additional dependencies. We can easily extend the code to include additional validation rules. The same approach could be used to validate any type of input, not just text inputs.