Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
py9mrg opened this issue Apr 10, 2021 · 9 comments
Closed
Labels
enhancement New feature or request

Comments

@py9mrg
Copy link

py9mrg commented Apr 10, 2021

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
Copy link
Author

py9mrg commented Apr 11, 2021

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
Copy link
Author

py9mrg commented Apr 11, 2021

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
Copy link
Owner

glin commented Aug 29, 2021

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 (#177 (comment)). 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.

@glin glin added the enhancement New feature or request label Aug 29, 2021
@py9mrg
Copy link
Author

py9mrg commented Aug 30, 2021

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
Copy link

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
Copy link
Author

py9mrg commented Dec 2, 2021

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
Copy link

melanieveneron commented Dec 2, 2021 via email

@py9mrg
Copy link
Author

py9mrg commented Dec 2, 2021

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

@glin
Copy link
Owner

glin commented Dec 5, 2021

@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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants