Theme-ui: Breakpoint objects/aliases

Created on 29 Aug 2019  路  10Comments  路  Source: system-ui/theme-ui

Hi there, is the below Styled System syntax supported in Theme UI? It doesn't appear to be working when using the pragma like this: (none of the styles are being applied at all)

<div 
sx={{
 bg: { _: "green", sm: "red", md: "blue" }, 
}} >

Thanks!

https://github.com/styled-system/styled-system/blob/master/docs/responsive-styles.md#using-objects

Most helpful comment

@jxnblk We're using theme-ui in our shared component library in our organisation and we really appreciate the { _: '12px', xl: '16px' } object style when using styled-system props. We get quite a few questions from devs regarding why this syntax doesn't exist with the sx prop.

It's a really nice syntax, as if you add/remove/change breakpoints, you don't need to update any arrays. It's also a lot more concise to code. We'd love to see it added :)

All 10 comments

Alternatively, is there a way to just call breakpoints on the fly?

My use case is that 99% of my layout simply uses 3 breakpoints, but things like the header navigation requires about 6.

Something like this would be a huge de-cluttering for my particular project :)

<nav 
sx={{
 bg: { 0: "green", 300: "red", 600: "blue", 1100 "yellow" }, 
}} >

Theme UI and @styled-system/css only support responsive array values. If you prefer using plain objects, use the standard media query syntax, e.g. '@media (min-width:40em)': {}

Hi @jxnblk.

Can you please explain why you only support responsive array values for breakpoints?
I feel like having an object map to min-widths is more resilient if we wanted to add _new_ breakpoints as well as being more declarative in the code.

I am also having the same issue, when adding new breakpoints. It's more resilient to break things

If you want to extra breakpoints in your SX objects, without writing a lot of boiler plate, you can utilize ES6 tag functions.

const bp = x => `@media (min-width:${x})` 

Now when you're trying to make a custom breakpoint you can simply write

<SomeComponent  sx={{
    bp`600px`:  {
       width: "100px";
    },
    ...  otherStyles
}}/>

@jxnblk We're using theme-ui in our shared component library in our organisation and we really appreciate the { _: '12px', xl: '16px' } object style when using styled-system props. We get quite a few questions from devs regarding why this syntax doesn't exist with the sx prop.

It's a really nice syntax, as if you add/remove/change breakpoints, you don't need to update any arrays. It's also a lot more concise to code. We'd love to see it added :)

I came up with this helper function for parsing objects that have responsive breakpoints and converting them to an array.

You will probably need to play with it a bit to fit your setup, but it's been working great.

import theme from 'path/to/theme.js'

export const parseResponsiveObjects = obj => {
    if (!obj) return obj

    const breakpointKeys = [
        '_',
        ...Object.keys(theme.breakpoints).filter(key => isNaN(parseInt(key))),
    ]

    // Found object that needs updated
    if (Object.keys(obj).filter(x => breakpointKeys.includes(x)).length > 0) {
        return breakpointKeys.map(bp => obj[bp] || null)
    } else {
        // Iterate over the properties
        for (var propertyName in obj) {
            // Any object that is not a simple value
            if (
                obj[propertyName] !== null &&
                typeof obj[propertyName] === 'object'
            ) {
                // Recurse into the object and write back the result to the object
                obj[propertyName] = parseResponsiveObjects(obj[propertyName])
            }
        }
    }

    return obj
}

We have it built into our components, so objects get parsed automatically, but you could use it something like this:

import { parseResponsiveObjects as pro } from 'path/to/helper/file'

<Box
    sx={pro({
        ':hover': {
            boxShadow: {
                _: '0 0 0 5px lightgray',
                sm: '0 0 0 5px gray',
                lg: '0 0 0 5px black',
            },
        },
    })}
/>

I created a custom helper function:

export const responsive = <T = number | string>(
    breakpoints: {
        [key in "xs" | "sm" | "md" | "lg"]?: T;
    }
): (T | null)[] => {
    return [
        breakpoints.xs ?? null,
        breakpoints.sm ?? null,
        breakpoints.md ?? null,
        breakpoints.lg ?? null,
    ];
};

which can be used in sx. For example: sx={{ width: responsive({ xs: "40px", lg: "100%" }), }}

I share the sentiment with others @jxnblk. While breakpoints array makes for a concise definition and usage, any refactoring can quickly get out of hand when these values shift by 1. I am not sure what the syntax would look like, but I'd personally find it better to explicitly define the array, e.g. [query.sm, query.md, query.lg].

I also find it very hard to read/maintain the array syntax [xx, yy, zz] - always have to go back to the theme and verify what were the responsive breakpoints values.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jxnblk picture jxnblk  路  4Comments

moshemo picture moshemo  路  3Comments

vojtaholik picture vojtaholik  路  3Comments

LeunensMichiel picture LeunensMichiel  路  3Comments

ekafyi picture ekafyi  路  4Comments