Manual#
Download this notebook from GitHub (right-click to download).
import math
import panel as pn
from panel_material_ui import (
Column, Container, Drawer, Paper, ButtonIcon, ThemeToggle, Typography, ToggleIcon, Row, Pagination, Grid
)
pn.extension()
In addition to the Page
component, Material components like Container
, Paper
, and others can be combined to manually define the layout of an application.
These building blocks provide more granular control over structure, spacing, and visual hierarchy when you need a fully custom page design.
In this reference guide we will discover a few ways we can use these components to generate a page-like layout.
LOREM_IPSUM = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
"""
def generate_pages(text: str, chars_per_page: int, num_pages: int) -> list[str]:
total_chars_needed = chars_per_page * num_pages
repeats = math.ceil(total_chars_needed / len(text))
full_text = text * repeats
return [
full_text[i*chars_per_page : (i+1)*chars_per_page]
for i in range(num_pages)
]
Building a Custom Layout with Container
and Paper
#
When manually designing a page, two key Material components often form the foundation: Container
and Paper
. The Container
sets the overall width, margins, and centering for your content, while the Paper
provides a surface with padding, elevation, and layout flexibility inside the container.
In this example, we start by wrapping the entire layout inside a Container
, which centers the content and constrains its width with width_option='sm'
.
Inside the container, a Paper
component acts as the main surface of the application — giving the content a card-like feel, adding padding (sx={"p": "1rem"}
), and stretching to fill the available height and width.
title = Typography('Lorem Ipsum', variant='h3', margin=(20, 30))
sidebar = Drawer('# Drawer', anchor='right', variant='temporary', size=300)
toggles = Row(
ThemeToggle(),
sidebar.create_toggle(),
styles={'position': 'absolute', 'top': "0", 'right': "0"}
)
pages = generate_pages(LOREM_IPSUM, 1000, 99)
pagination = Pagination(count=99, align=('center', 'end'), styles={'marginTop': "auto"})
Container(
Paper(
title,
toggles,
sidebar,
pn.rx(pages)[pagination],
pagination,
elevation=3,
sizing_mode='stretch_both',
sx={"p": "1rem"}
),
margin=(10, 0),
height=580,
width_option='sm'
).preview(sizing_mode='stretch_width', height=600)
Within the Paper
, we arrange the individual UI elements:
A
Typography
component displays the title, styled with custom margins.A
Row
positions the theme toggle and sidebar toggle buttons absolutely in the top-right corner.A
Drawer
provides a collapsible sidebar anchored to the right side.The main content is a set of paginated pages, dynamically generated and linked to a
Pagination
control at the bottom.
By combining Container
and Paper
, you can quickly establish a clean, responsive base for your application — layering in more interactive components as needed while maintaining full control over layout and styling.
Building a Dashboard layout with Grid
and Drawer
#
This example builds a simple dashboard layout by combining a persistent Drawer
, a title, a Grid
for the main content, and floating toggle controls.
A
Drawer
is anchored to the left side of the page, usingvariant='persistent'
so it pushes the content when open instead of overlaying it. It is styled with padding to align its content below the fixed title.A
Typography
component displays the dashboard title, positioned with a left margin to avoid overlap with the drawer.The main content is arranged in a
Grid
, with two charts placed side-by-side on medium and larger screens (md=6
each) and stacked on smaller screens (xs=12
), followed by a full-width chart.Each chart is wrapped in a
Paper
component to provide padding, elevation, and a consistent card-like appearance.A
ThemeToggle
and a drawer toggle button are positioned absolutely in the top-right corner for easy access, without affecting the flow of the main layout.The overall layout is built with a
Row
, placing theDrawer
beside the main content and the floating controls.
This structure keeps the layout responsive, clean, and modular, while giving the user control over both theme and sidebar visibility.
title = Typography("My Dashboard", variant="h4", margin=(0, 0, 0, 50))
drawer = Drawer(
Typography("I'm in a Drawer!", variant="h6"),
variant="persistent",
anchor="left",
styles={"height": "100%"},
sx={"paddingTop": "50px"}
)
theme_toggle = ThemeToggle(styles={"position": "fixed", "right": "0", "zIndex": "10001"})
render_content = lambda text: Paper(Typography(text, variant='h6'), elevation=2, sx={"p": "1rem"}, sizing_mode="stretch_both")
grid = Grid(
Grid(
render_content("Chart 1"),
size={"md": 6, "xs": 12}
),
Grid(
render_content("Chart 2"),
size={"md": 6, "xs": 12}
),
Grid(
render_content("Chart 3"),
size={"md": 12, "xs": 12}
),
container=True,
column_spacing=2,
row_spacing=2,
sizing_mode='stretch_both',
margin=(0, 20, 20, 20)
)
main = Column(title, grid)
toggle = drawer.create_toggle(styles={"position": "fixed", "zIndex": "10001"})
Row(
drawer,
main,
theme_toggle,
toggle,
sizing_mode="stretch_width"
).preview(sizing_mode='stretch_width')
These are just two ways in which components can be combined to create a custom application layout.
Download this notebook from GitHub (right-click to download).