Skip to content
Back to skills

2562 Page Layouts 7aa85757

ASecurity

This reference covers the page-level layout functions in bslib that structure entire Shiny applications. These are the top-level containers that determine the overall architecture of your app.

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
dataperformancedocumentation

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 2562-page-layouts_7aa85757 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 2562 Page Layouts 7aa85757?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 2562 Page Layouts 7aa85757
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-2562-page-layouts-7aa85757/badge)](https://www.skillsdirectory.com/skills/tools-only-2562-page-layouts-7aa85757)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
# Page Layouts in bslib

This reference covers the page-level layout functions in bslib that structure entire Shiny applications. These are the top-level containers that determine the overall architecture of your app.

## Table of Contents

- [Dashboard Layouts](#dashboard-layouts)
  - [page_sidebar()](#page_sidebar)
  - [page_navbar()](#page_navbar)
  - [page_fillable()](#page_fillable)
- [Basic Page Layouts](#basic-page-layouts)
- [Filling vs Scrolling Behavior](#filling-vs-scrolling-behavior)
- [Mobile Considerations](#mobile-considerations)
- [Production Best Practices](#production-best-practices)

## Dashboard Layouts

### page_sidebar()

The primary function for creating single-page dashboards with a sidebar and main content area.

**Basic structure:**
```r
ui <- page_sidebar(
  title = "My dashboard",
  sidebar = sidebar("Sidebar content"),
  "Main content area"
)
```

**Best practice:** Keep inputs in the `sidebar` and outputs in the main content area. Wrap outputs in `card()` and sidebar contents in `sidebar()` for titles and custom styling.

**Example with cards:**
```r
ui <- page_sidebar(
  title = "Penguins Dashboard",
  sidebar = sidebar(
    selectInput("species", "Species", choices = unique(penguins$species))
  ),
  card(
    full_screen = TRUE,
    card_header("Bill Length"),
    plotOutput("bill_length")
  ),
  card(
    card_header("Summary Statistics"),
    verbatimTextOutput("summary")
  )
)
```

**Key parameters:**
- `title`: App title displayed at the top
- `sidebar`: A `sidebar()` object with inputs/controls
- `theme`: Optional `bs_theme()` object for styling
- `fillable`: Whether the page should fill the viewport height (default TRUE)
- `fillable_mobile`: Whether fillable behavior applies on mobile (default FALSE)
- `class = "bslib-page-dashboard"`: Adds a light gray background behind the main area, which looks best when cards are used as the primary content containers

### page_navbar()

Use `page_navbar()` for multi-page dashboards with a top navigation bar. Each page is defined with `nav_panel()`.

**Basic structure:**
```r
ui <- page_navbar(
  title = "Multi-Page Dashboard",
  nav_panel("Page 1", "Content for page 1"),
  nav_panel("Page 2", "Content for page 2"),
  nav_panel("Page 3", "Content for page 3")
)
```

**With sidebar:**
```r
ui <- page_navbar(
  title = "Penguins Dashboard",
  sidebar = sidebar(
    selectInput("color_by", "Color by", choices = c("species", "island"))
  ),
  nav_spacer(),
  nav_panel("Bill Length", card(...)),
  nav_panel("Bill Depth", card(...)),
  nav_panel("Body Mass", card(...)),
  nav_item(tags$a("Documentation", href = "https://example.com"))
)
```

**Important caveat:** `page_navbar()`'s `sidebar` argument puts the same sidebar on every page. If you need different sidebars per page or conditional sidebar contents, see the [sidebars reference](sidebars.md) for strategies.

**Key parameters:**
- `title`: App title in the navbar
- `sidebar`: Optional `sidebar()` shown on all pages
- `id`: ID for tracking the active page (accessible as `input$<id>`)
- `fillable`: Can be TRUE (all pages), FALSE (no pages), or a vector of page names
- `theme`: Optional `bs_theme()` object

**Dashboard appearance:** Add `class = "bslib-page-dashboard"` to individual `nav_panel()` containers (not the `page_navbar()` itself) to get a light gray background on specific pages:

```r
page_navbar(
  title = "My App",
  nav_panel("Dashboard", class = "bslib-page-dashboard",
    card(...),
    card(...)
  ),
  nav_panel("About", "Plain white background here")
)
```

**Navigation helpers:**
- `nav_spacer()`: Adds spacing/pushes subsequent items right
- `nav_item()`: Adds arbitrary HTML (e.g., links) to navbar
- `nav_menu()`: Creates dropdown menus

### page_fillable()

A screen-filling page layout where content grows/shrinks to fit the browser window. This is the foundation for filling layouts in bslib.

**Key behavior:** Direct children of `page_fillable()` become fill items, meaning they'll resize to fill available space. This is ideal for dashboards where you want outputs to adapt to the viewport size. Typical usage wraps `layout_columns()` (or similar layout containers) and `card()` components as direct children.

**When to use:**
- Dashboards with plots/maps that should expand to fill the screen
- Single-page apps where all content should be visible without scrolling
- Apps with dynamic layouts that adapt to window size

Note: `page_sidebar()` and `page_navbar()` are built on top of `page_fillable()` and inherit its filling behavior by default.

## Basic Page Layouts

Beyond dashboard layouts, bslib provides traditional page functions:

- **`page_fluid()`**: Full-width page that resizes horizontally but scrolls vertically
- **`page_fixed()`**: Fixed-width page (940px default) that scrolls vertically
- **`page()`**: Most flexible option with manual control

These are useful when you don't want filling behavior and prefer traditional scrolling layouts.

## Filling vs Scrolling Behavior

### Filling Layouts (Default for Dashboard Pages)

Both `page_sidebar()` and `page_navbar()` default to `fillable = TRUE`, where outputs are encouraged to grow/shrink to fit the browser window.

**Benefits:**
- Content adapts to available screen space
- Professional dashboard appearance
- No scrolling needed when content fits

**Considerations:**
When content has large intrinsic minimum heights:
- Set `height` on cards that shouldn't resize
- Set `min_height` on cards that need a minimum size
- Set `max_height` on cards that shouldn't grow too large

**Example:**
```r
layout_columns(
  card(min_height = 200, max_height = 400, plotOutput("plot1")),
  card(height = 300, lorem::ipsum(10))
)
```

### Scrolling Layouts

For pages with many outputs or long content, set `fillable = FALSE` to disable filling behavior. This causes outputs to fall back to their default heights (~400px for plots) with page scrolling enabled. Pass `fillable = FALSE` directly to `page_sidebar()` or `page_navbar()`.

**For page_navbar(), use selective filling:**
```r
ui <- page_navbar(
  title = "Mixed Layout",
  fillable = c("Overview", "Analysis"),  # Only these pages fill
  nav_panel("Overview", ...),      # Fills viewport
  nav_panel("Analysis", ...),      # Fills viewport
  nav_panel("Details", ...)        # Scrolls normally
)
```

## Mobile Considerations

By default, filling layout is disabled on mobile devices to prevent awkward resizing on small screens. Set `fillable_mobile = TRUE` on `page_sidebar()` or `page_navbar()` to enable filling on mobile.

**Best practices for mobile:**
- Use `min_height` on cards to prevent excessive shrinking
- Sidebars collapse by default on mobile (configurable via `sidebar(open = ...)`)
- Test responsive breakpoints using browser dev tools
- Consider using `layout_column_wrap()` for responsive multi-column layouts

## Production Best Practices

### Pin Bootstrap Version

Before deploying to production, hard-code the Bootstrap version to prevent breakage on updates. Pass `theme = bs_theme(version = 5)` to any page function. This ensures your app uses Bootstrap 5 (recommended for modern features) and won't break if bslib's default version changes.

### Theming

Pass a `bs_theme()` object to the `theme` parameter of any page function to customize appearance. See [theming.md](theming.md) for comprehensive theming guidance.

### Plot Styling

Use the `thematic` package to ensure plots match your theme. Call `thematic::thematic_shiny()` in your server function or `app.R` to automatically style `plotOutput()` to match your CSS theme colors.

### Performance Tips

- For apps with many outputs, consider using `fillable = FALSE` and letting users scroll
- Use `card(full_screen = TRUE)` to allow expanding individual visualizations
- Consider using `navset_card_tab()` to organize related outputs within a single card
- Profile your app with `profvis` to identify rendering bottlenecks

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.