DetailsList {shiny.fluent}R Documentation

DetailsList

Description

A details list (DetailsList) is a robust way to display an information-rich collection of items, and allow people to sort, group, and filter the content. Use a details list when information density is critical.

For more details and examples visit the official docs. The R package cannot handle each and every case, so for advanced use cases you need to work using the original docs to achieve the desired result.

Usage

DetailsList(...)

Arguments

...

Props to pass to the component. The allowed props are listed below in the Details section.

Details

Virtualization will add and remove pages of items as the user scrolls them into the visible range. This benefits larger list scenarios by reducing the DOM on the screen, but can negatively affect performance for smaller lists.

The default implementation will virtualize when this callback is not provided.

Falls back to window 'resize' event.

Value

Object with shiny.tag class suitable for use in the UI of a Shiny app.

Best practices

Layout

Content

⁠[capitalization]⁠: https://docs.microsoft.com/style-guide/capitalization

FAQ

My scrollable content isn't updating on scroll. What should I do?

Add the data-is-scrollable="true" attribute to your scrollable element containing the DetailsList.

By default, the List used within DetailsList will use the body element as the scrollable element. If you contain the List within a scrollable div using overflow: auto or scroll, the List needs to listen for scroll events on that element instead. On initialization, the List will traverse up the DOM looking for the first element with the data-is-scrollable attribute to know which element to listen to for knowing when to re-evaulate the visible window.

My List is not re-rendering when I mutate its items. What should I do?

To determine if the List within DetailsList should re-render its contents, the component performs a referential equality check within its shouldComponentUpdate method. This is done to minimize the performance overhead associated with re-rendering the virtualized List pages, as recommended by the React documentation.

As a result of this implementation, the inner List will not determine it should re-render if the array values are mutated. To avoid this problem, we recommend re-creating the items array backing the DetailsList by using a method such as Array.prototype.concat or ES6 spread syntax shown below:

public appendItems(): void {
  const { items } = this.state;

  this.setState({
    items: [...items, ...['Foo', 'Bar']]
  })
}

public render(): JSX.Element {
  const { items } = this.state;

  return <DetailsList items={items} />;
}

By re-creating the items array without mutating the values, the inner List will correctly determine its contents have changed and it should then re-render with the new values.

Examples

# Example 1
library(shiny)
library(shiny.fluent)

items <- list(
  list(key = "1", name = "Mark", surname = "Swanson"),
  list(key = "2", name = "Josh", surname = "Johnson")
)

columns <- list(
  list(key = "name", fieldName = "name", name = "Name"),
  list(key = "surname", fieldName = "surname", name = "Surname")
)


ui <- function(id) {
  ns <- NS(id)
  DetailsList(items = items, columns = columns)
}

server <- function(id) {
  moduleServer(id, function(input, output, session) {})
}

if (interactive()) {
  shinyApp(ui("app"), function(input, output) server("app"))
}

# Example 2
library(shiny)
library(shiny.fluent)

# Custom columns text alignment and formatting
items <- list(
  list(
    key = "1",
    name = "Mark",
    number = "2"
  ),
  list(
    key = "2",
    name = "Josh",
    number = "1"
  )
)

columns <- list(
  list(
    key = "name",
    fieldName = "name",
    name = "Name"
  ),
  list(
    key = "number",
    fieldName = "number",
    name = "Number"
  )
)

ui <- function(id) {
  DetailsList(
    items = items,
    columns = columns,
    onRenderItemColumn = JS("(item, index, column) => {
      const fieldContent = item[column.fieldName]
      switch (column.key) {
        case 'name':
          return React.createElement(
            'span',
            {
              style: { textAlign: 'right', width: '100%', display: 'block' }
            },
            fieldContent
          );
        case 'number':
          return React.createElement(
            'span',
            {
              style: { textAlign: 'left', width: '100%', display: 'block' }
            },
            `%${fieldContent}`
          );
        default:
          return React.createElement('span', null, fieldContent);
      }
    }")
  )
}

server <- function(id) {
  moduleServer(id, function(input, output, session) {})
}

if (interactive()) {
  shinyApp(ui("app"), function(input, output) server("app"))
}

# Example 3
library(shiny)
library(shiny.fluent)

# Selecting rows in DetailsList
CustomComponents <- tags$script(HTML("(function() {
  const React = jsmodule['react'];
  const Fluent = jsmodule['@fluentui/react'];
  const Shiny = jsmodule['@/shiny'];
  const CustomComponents = jsmodule['CustomComponents'] ??= {};

  function useSelection(inputId) {
    const selection = React.useRef(new Fluent.Selection({
      onSelectionChanged() {
        const value = this.getSelectedIndices().map(i => i + 1); // R uses 1-based indexing.
        Shiny.setInputValue(inputId, value);
      }
    }));
    return selection.current;
  }

  CustomComponents.DetailsList = function DetailsList({ inputId, ...rest }) {
    const selection = useSelection(inputId);
    return React.createElement(Fluent.DetailsList, { selection, ...rest });
  }
})()"))

DetailsList.shinyInput <- function(inputId, ...) {
  shiny.react::reactElement(
    module = "CustomComponents",
    name = "DetailsList",
    props = shiny.react::asProps(inputId = inputId, ...),
    deps = shinyFluentDependency()
  )
}

items <- list(
  list(name = "Apple"),
  list(name = "Banana"),
  list(name = "Cherry")
)

ui <- function(id) {
  ns <- NS(id)
  tagList(
    CustomComponents,
    DetailsList.shinyInput(ns("selection"), items = items),
    textOutput(ns("text"))
  )
}

server <- function(id) {
  moduleServer(id, function(input, output, session) {
    output$text <- renderText(paste(input$selection, collapse = ", "))
  })
}

if (interactive()) {
  shinyApp(ui("app"), function(input, output) server("app"))
}

[Package shiny.fluent version 0.4.0 Index]