glin / reactable

Interactive data tables for R
https://glin.github.io/reactable
Other
627 stars 80 forks source link

Vertical alignment of cells when other columns contain multiple lines #142

Closed py9mrg closed 3 years ago

py9mrg commented 3 years ago

Hello,

I can't work out a way to align cells vertically (i.e. the contents in the middle) when other columns contain entries that span multiple lines. I've tried, colDef, CSS, html within the cells, everything. It all seems to work within each line of the cell and not across the full cell. If that makes sense? Compare the two results below (ignore horizontal alignment), hopefully it makes more sense:

test_tbl <- tibble::tibble(a = c("really really really really really really long entry"), b = rep("short"))

library(reactable)
reactable(test_tbl,
          columns = list(a = colDef(width = 200), a = colDef(width = 200)))

library(DT)
datatable(test_tbl,
          options = list(columnDefs = list(list(width = '200px', targets = c(1, 2)))))

Created on 2021-04-10 by the reprex package (v2.0.0)

py9mrg commented 3 years ago

Ok so I've fudged two potential solutions to this (assuming there isn't something obvious I'm missing - which is quite possible).

  1. Place a half line-height span element with some default text either side of the actual cell contents - setting color to white so the text doesn't show - e.g. write a function that changes a cell from value to something like <span style = 'line-height:10px; color:white;'>TEXT</span><span>value</span><span style = 'line-height:10px; color:white;'>TEXT</span>. The function also needs to check that no other columns have any text longer than the column width. This all then shifts each bit of text in a cell with one line down to the middle of the cell as required. But the whole code needed is pretty hacky and not very robust to changes.
  2. Use stringr::str_trunc to shorten any strings such that they're shorter than the column width and then the table never has any rows with multiple lines (and then use a tooltip with the full text, if needed). This is a little simpler and less hacky - but I'm guessing not very robust if you use resizable columns (although I haven't tested).

I was hoping for something as simple as some CSS and/or HTML that would accept vertical-align: middle; or similar - but I just can't get anything to work as it all seems to work within each line of each row, not within each row overall. I guess the way React Table renders the tables means it only thinks about lines not the cell as a whole entity - but we're really way beyond the limits of my understanding of CSS, HTML, React etc etc.

py9mrg commented 3 years ago

Oh my God, what a moron I am. Had one last look at the documentation as soon as I posted the above and noticed the Star Wars demo. How did I miss that?! All it needs is:

theme = reactableTheme(
    # Vertically center cells
    cellStyle = list(display = "flex", flexDirection = "column", justifyContent = "center")
  ))

in the reactable call. Ignore me! Although hopefully the above might prove useful for someone, maybe point 2 in previous comment is a nice way to handle long cell entries if you don't want to end up with some rows thicker than others.

glin commented 3 years ago

Hi, vertical alignment is now supported in the development version:

  • Cell content can now be vertically aligned using the new vAlign and headerVAlign arguments in colDef(), and the new headerVAlign argument in colGroup() (#142, #177).

Sorry for that example being so hidden before. Vertical alignment is tricky in reactable for many reasons, and even the theme method in the docs can break in some cases (https://github.com/glin/reactable/issues/177#issuecomment-882135466). You also can't just set vertical-align on cells because reactable doesn't use an HTML table layout.

In the next version, you can replace those theme styles with the column option, which should work more reliably. I've also added a more prominent example for vertical alignment in the examples: https://glin.github.io/reactable/articles/examples.html#vertical-alignment.

py9mrg commented 3 years ago

That's brilliant. And no need to apologise, the example wasn't hidden it was totally my fault for skimming too quickly - there's just so many things you can do with reactable, and your docs packed full of useful examples. In fact, they're right up amongst the best I've read of any R package.

melanieveneron commented 2 years ago

Hi! I'm actually in a pickle on this. I cant use the new version yet because our app is being deployed next week. I need my headers to align to the bottom, but using the theme options for headerStyle, I can only vertically center the headers. Any ideas from folks on this thread?

py9mrg commented 2 years ago

Hello @melanierogala have you seen my comment above here. You don't need the latest version to use this? You would just change the justify argument to "bottom" I assume. That might not be what you're looking for though as I'm not sure I fully understand your question.

melanieveneron commented 2 years ago

Right! I tried this and was able to use it to center, but "bottom" or "baseline" didn't work

On Thu, Dec 2, 2021 at 6:11 AM py9mrg @.***> wrote:

Hello @melanierogala https://github.com/melanierogala have you seen my comment above here https://github.com/glin/reactable/issues/142#issuecomment-817331507. You don't need the latest version to use this? You would just change the justify argument to "bottom" I assume. That might not be what you're looking for though as I'm not sure I fully understand your question.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/glin/reactable/issues/142#issuecomment-984662656, or unsubscribe https://github.com/notifications/unsubscribe-auth/AQVBSF56GHYUWZE252CIASLUO55A3ANCNFSM42WYXTPA .

py9mrg commented 2 years ago

Strange, I'm not sure. Maybe the package author can help. It would be good to have an MWE (reprex) to test.

glin commented 2 years ago

@melanierogala Can you try justifyContent = "flex-end"? I think that should work in the current CRAN version. Here's an example with bottom-aligned headers, using reactableTheme():

library(reactable)
library(dplyr)
library(htmltools)

data <- starwars[1:6, ] %>%
  select(character = name, height, mass, gender, homeworld, species)

reactable(
  data,
  columns = list(
    character = colDef(
      name = "Character / Species",
      # Show species under character names
      cell = function(value, index) {
        species <- data$species[index]
        species <- if (!is.na(species)) species else "Unknown"
        div(
          div(style = list(fontWeight = 600), value),
          div(style = list(fontSize = 12), species)
        )
      }
    ),
    species = colDef(show = FALSE)
  ),
  theme = reactableTheme(
    # Align headers to the bottom
    headerStyle = list(display = "flex", flexDirection = "column", justifyContent = "flex-end")
  ),
  bordered = TRUE,
  width = 600
)

flex-end is what flexbox uses to align stuff to the end, or bottom in this case (https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content).