develop

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:

NameFrom width (dp)
xs0
sm576
md768
lg992
xl1200
xxl1400

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

python
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.

python
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"),
)
ComponentUse it for
ContainerCentered page column. Max width 540 / 720 / 960 / 1140 / 1320 dp from sm up. fluid=True fills the width.
Row, Col12-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, GridItemEqual 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.
FlexFlexbox with short props: direction, gap, align, justify, wrap.
HStack, VStackChildren side by side or stacked, spacing apart.
CenterCenters its children on both axes.
SpacerTakes the free space in a Flex or stack, or a fixed size.
Show, HideRender 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.

python
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 AND

Each 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

python
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.