Layout with dynamically resizable cards
Nobody has claimed this yet.
- Dominant language
- SCSS
- Stars
- 569
- Forks
- 72
- Avg merge
- 1d 2h
- Merged PRs (30d)
- 5
Description
It is useful to be able to dynamically resize cards in order to focus on particular cards without having to use the existing full_screen feature.
I’ve built a working prototype for my use case using https://split.js.org/. It works well with fillable cards and I think it would be really cool to have something like this in the package itself.
Demo:
Code:
library(shiny)
library(bslib)
library(reactable)
library(plotly)
library(leaflet)
library(dplyr)
# --- CSS ---
split_css <- HTML("
html, body, .bslib-page-fillable { height: 100%; margin: 0; }
.grid-container { display: flex; width: 100%; height: 100%; min-height: 0; }
.left-column, .right-column { display: flex; flex-direction: column; flex: 0 0 auto; min-width: 0; min-height: 0; }
.top-row, .bottom-row { border: none; border-radius: 0; margin: 0 !important; min-height: 0; min-width: 0; }
.gutter.gutter-horizontal { width: 10px; cursor: ew-resize; background: var(--bs-border-color, #ddd); }
.gutter.gutter-vertical { height: 10px; cursor: ns-resize; background: var(--bs-border-color, #ddd); }
")
# --- JS ---
split_js <- HTML("
$(function() {
if (typeof Split === 'undefined') return;
let colSizes = JSON.parse(localStorage.getItem('col-sizes') || '[50,50]');
Split(['.left-column', '.right-column'], {
sizes: colSizes, gutterSize: 10, direction: 'horizontal',
cursor: 'ew-resize',
onDragEnd: s => localStorage.setItem('col-sizes', JSON.stringify(s))
});
let leftRows = JSON.parse(localStorage.getItem('left-rows') || '[50,50]');
Split(['.left-column > .top-row', '.left-column > .bottom-row'], {
sizes: leftRows, gutterSize: 10, direction: 'vertical',
cursor: 'ns-resize',
onDragEnd: s => localStorage.setItem('left-rows', JSON.stringify(s))
});
let rightRows = JSON.parse(localStorage.getItem('right-rows') || '[50,50]');
Split(['.right-column > .top-row', '.right-column > .bottom-row'], {
sizes: rightRows, gutterSize: 10, direction: 'vertical',
cursor: 'ns-resize',
onDragEnd: s => localStorage.setItem('right-rows', JSON.stringify(s))
});
});
")
# --- UI ---
ui <- page_fillable(
theme = bs_theme(),
tags$head(
tags$script(src = "https://unpkg.com/split.js/dist/split.min.js"),
tags$script(split_js),
tags$style(split_css)
),
div(
class = "grid-container",
div(
class = "left-column",
card(
class = "top-row",
card_header("Data table"),
reactableOutput("tbl")
),
card(
class = "bottom-row",
card_header("Scatter plot"),
plotlyOutput("plt")
)
),
div(
class = "right-column",
card(
class = "top-row",
card_header("Map view"),
leafletOutput("map")
),
card(
class = "bottom-row",
card_header("Histogram"),
plotOutput("hist")
)
)
)
)
# --- SERVER ---
server <- function(input, output, session) {
df <- tibble(
id = 1:10,
x = rnorm(10),
y = rnorm(10),
lat = 60.39 + runif(10, -0.01, 0.01),
lng = 5.33 + runif(10, -0.01, 0.01)
)
output$tbl <- renderReactable({
reactable(
df,
compact = TRUE,
columns = list(
x = colDef(format = colFormat(digits = 2)),
y = colDef(format = colFormat(digits = 2)),
lat = colDef(format = colFormat(digits = 2)),
lng = colDef(format = colFormat(digits = 2))
)
)
})
output$plt <- renderPlotly(plot_ly(df, x = ~x, y = ~y, color = ~id, mode = "markers"))
output$map <- renderLeaflet(leaflet(df) |> addTiles() |> addCircleMarkers(~lng, ~lat, label = ~id))
output$hist <- renderPlot({
hist(df$x, col = "#3182bd", border = "white", main = "Distribution of X", xlab = "X values")
})
}
shinyApp(ui, server)
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing bslib's existing card layout and full_screen feature, then compare the supplied Split.js prototype and its CSS/JavaScript behavior. Define how resizing should work within the package, including supported card arrangements and persistence, and verify the result with an equivalent fillable-card layout.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- css, javascript, r
- Domain
- frontend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100