Search code examples
cssrshinyreactable

How to prevent text overflow in reactable.extras text field?


I have a shiny app with a css style-sheet. Within the shiny app i use reactable and reactable.extras to capture text inputs.

library(shiny)
library(dplyr)
library(reactable)
library(reactable.extras)

df <- tibble(text_col = rep(NA, 5))

tweak_css <- function(file = "style.css") {

  tags$link(rel= "stylesheet",
            type = "text/css",
            href = file) |>
            tags$head()

}


shinyApp(
  ui = fluidPage(
    tweak_css(),
    reactable_extras_dependency(),
    reactableOutput("react"), 
    dataTableOutput("out")
  ),
  server = function(input, output) {
    rv <- reactiveValues(data = df)
    
    
      
    output$react <- renderReactable({
      reactable(
        rv$data,
        
        columns = list(
          
          text_col = colDef(
          cell = text_extra(id = "text", 
                            class = "text-extra"))
        )
        
      )
    })
    
    text_d <- reactive({ input$text}) %>% debounce(3000)    
    
    observeEvent(text_d(), {
      
      rv$data[text_d()$row, text_d()$column] <- text_d()$value
      
    })   
    
    output$out <- renderDataTable({
      rv$data
    })
  }
)

The accompanying style-sheet defines the size of the text input field. I fail to manage preventing text overflow.

.text-extra {
  
  width: 80px;
  height: 80px;
  word-break: break-word;
  
}

I tried almost everything described here How to prevent text from overflowing in CSS? but it does not solve the problem. What can i do that the user can enter text with line breaks?

EDIT:

The use of DT seems not suitable since my original application has some more columns with checkboxes included.


Solution

  • What can i do that the user can enter text with line breaks?

    You could wrap the text_extra function and give it the correct style.

    out1

    Code

    library(shiny)
    library(dplyr)
    library(reactable)
    library(reactable.extras)
    
    df <- tibble(text_col = rep(NA, 5))
    
    text_extra <- function(id = NULL, class = NULL) {
      function(value, index, name) {
        div(
          class = class,
          style = "white-space: pre-wrap !important; word-break: break-all !important;",
          textAreaInput(
            inputId = paste0(id, "_", index, "_", name),
            label = NULL,
            value = value,
            resize = "none",
            width = "80px",
            height = "80px"
          )
        )
      }
    }
    shinyApp(
      ui = fluidPage(
        reactable_extras_dependency(),
        reactableOutput("react"), 
        dataTableOutput("out")
      ),
      server = function(input, output) {
        rv <- reactiveValues(data = df)
        
        output$react <- renderReactable({
          reactable(
            rv$data,
            columns = list(text_col = colDef(cell = text_extra(id = "text", class = "text-extra")))
          )
        })
        
        text_d <- reactive({ input$text}) %>% debounce(3000)    
        
        observeEvent(text_d(), {
          
          rv$data[text_d()$row, text_d()$column] <- text_d()$value
          
        })   
        
        output$out <- renderDataTable({
          rv$data
        })
      }
    )
    

    With datatable and checkboxes

    out2

    library(shiny)
    library(dplyr)
    library(DT)
    
    # Create sample data
    df <- tibble(
      text_col = rep(NA, 5),
      yes_no = rep(FALSE, 5)
    )
    
    shinyApp(
      ui = fluidPage(
        DTOutput("table")
      ),
      
      server = function(input, output, session) {
        rv <- reactiveValues(data = df)
        
        output$table <- renderDT({
          datatable(
            rv$data,
            editable = list(
              target = 'cell',
              disable = list(columns = c(2))  # Enable editing for text column only
            ),
            selection = "none",
            options = list(
              columnDefs = list(
                list(
                  targets = 2,  # yes_no column index (1-based)
                  render = JS("
                    function(data, type, row, meta) {
                      if (type === 'display') {
                        return '<input type=\"checkbox\"' + 
                               (data ? ' checked' : '') + 
                               ' onclick=\"(' + function(el) {
                                 var cell = el.parentNode;
                                 var row = cell.parentNode;
                                 var rowIdx = row.rowIndex;
                                 var colIdx = cell.cellIndex;
                                 Shiny.setInputValue(\'checkbox_click\', 
                                   {row: rowIdx, checked: el.checked, col: colIdx}, 
                                   {priority: \'event\'}
                                 );
                               } + ')(this)\">';
                      }
                      return data;
                    }")
                )
              )
            )
          )
        })
        
        observeEvent(input$table_cell_edit, {
          info <- input$table_cell_edit
          rv$data[info$row, info$col] <- info$value
        })
        
        observeEvent(input$checkbox_click, {
          info <- input$checkbox_click
          print(info)
          rv$data$yes_no[info$row] <- info$checked  # Add 1 because JS is 0-based
          print(rv$data)
        })
      }
    )