Responsive layout
One code base for phones, tablets, desktop windows and the browser. Breakpoints work like CSS media queries, and crossing one updates only the affected views, without a re-render.
Breakpoints
The window width in dp picks the breakpoint. The default table matches Bootstrap:
| Name | From width (dp) |
|---|---|
xs | 0 |
sm | 576 |
md | 768 |
lg | 992 |
xl | 1200 |
xxl | 1400 |
A breakpoint map such as {"base": 1, "md": 3} takes the value of the largest breakpoint at or below the current one, mobile first. base means "from 0".
Breakpoints in styles
A map works as a single style value, or as a whole style block (like Tailwind's md: prefix).
from pyxpo import StyleSheet
styles = StyleSheet.create({
"page": {"padding": {"base": 12, "lg": 32},
"flexDirection": {"base": "column", "md": "row"}},
"card": {"base": {"padding": 8}, "md": {"padding": 24, "gap": 16}},
})Layout components
Every layout prop below accepts a plain value or a breakpoint map.
from pyxpo import Container, Row, Col, Grid, GridItem, Flex, Spacer, Show, Hide, Text
Container(
Row(
Col(Text("Main"), span={"base": 12, "md": 8}),
Col(Text("Side"), span={"base": 12, "md": 4}),
gutter=16,
),
Grid(*cards, columns={"base": 1, "sm": 2, "lg": 4}, gap=12),
Grid(*cards, min_item_width=220), # as many 220 dp columns as fit
Grid(GridItem(hero, span=2), a, b, columns=3),
Flex(logo, Spacer(), menu, direction={"base": "column", "md": "row"}, gap=12, align="center"),
Show(Sidebar(), above="lg"),
Hide(BottomTabs(), above="lg"),
)| Component | Use it for |
|---|---|
Container | Centered page column. Max width 540 / 720 / 960 / 1140 / 1320 dp from sm up. fluid=True fills the width. |
Row, Col | 12-column grid. Col(span=...) takes span / 12 of the row. span="auto" is content width, None an equal share, 0 hides the column. offset pushes it right. |
Grid, GridItem | Equal columns that wrap, like CSS grid repeat(n, 1fr). columns=3, or min_item_width=220 to fit as many as the width allows. GridItem(span=2) spans columns. |
Flex | Flexbox with short props: direction, gap, align, justify, wrap. |
HStack, VStack | Children side by side or stacked, spacing apart. |
Center | Centers its children on both axes. |
Spacer | Takes the free space in a Flex or stack, or a fixed size. |
Show, Hide | Render children only at some breakpoints: above="lg", below="md" or only="md". |
Hooks
Use a hook when the component tree itself must change, not only its styles.
from pyxpo import useBreakpoint, useBreakpointValue, useMediaQuery
bp = useBreakpoint() # "md"
cols = useBreakpointValue({"base": 1, "md": 2, "xl": 3})
wide = useMediaQuery("md") # md and up
landscape = useMediaQuery(orientation="landscape")
tablet_only = useMediaQuery(only="md")
narrow = useMediaQuery(down="lg", min_width=400) # conditions combine with ANDEach hook re-renders the component only when its result changes, not on every pixel of a window resize. snake_case names work too: use_breakpoint, use_breakpoint_value, use_media_query.
Your own breakpoints
from pyxpo import StyleSheet
StyleSheet.configure(breakpoints={"phone": 0, "tablet": 600, "desktop": 1024})
styles = StyleSheet.create({"title": {"fontSize": {"phone": 20, "tablet": 26, "desktop": 32}}})base is reserved. pyxpo.responsive.set_breakpoints({...}) does the same without themes.
Try layouts without an emulator: pyxpo run web has a device preview with phone and tablet frames, rotate, zoom and a breakpoint ruler.