Is your feature request related to a problem? Please describe.
Currently, the Theme object is flat. We're compliant with System UI Theme specification, so scales have to be flat, but Variants (and there are quite a lot of them), and options (similarly) don't have to be, and they're not _as important_ as scales.
Right now we kind of enforce on the user to keep their theme object "in order" manually, with whitespaces, regions or manual sorting. Somebody with an ESLint rule sorting object keys will have a really bad time reading interweaved scales, variants and options.
Describe the solution you'd like
I think we could keep them nested under variants and options properties.
Of course, we'd have deprecate the old API and support both scenarios for a while, what's a bit annoying from maintenance perspective.
Describe alternatives you've considered
Leaving it as it is.
Additional context
We might have even more options in the near future.

@lachlanjc @atanasster @dcastil, what do you think?
I'm not sure if I can follow you. Theme UI scales don't need to be flat. 馃
But I also think that variants being at the top level could get a little messy. In my customized Theme UI implementation at work I created an object called variants and in the css() function I did something similar to:
if (key === 'variant') {
- const variant = css(get(theme, val as string))(theme)
+ const variant = css(get(theme.variants, val as string))(theme)
result = { ...result, ...variant }
continue
}
We could do this here as well.
Theme UI scales don't need to be flat. thinking
Sorry for the confusion. They're on the top level of the theme object, that's what I meant.
i.e. theme.colors not theme.scales.colors.
And that's okay, but I think we could do theme.options.useBodyStyles and theme.variants.buttons.
Ahh got it! I think theme.scales.colors would be a little boilerplaity as this adds one more level to the "hello world" theme. But I'd totally be up to moving options and variants from the top level into a separate object.
Conceptually it would make sense to put the scales into a dedicated object, but is it worth to break with the theme specification? 馃 Would be cool to have input from more people on this.
Yeah, I've thought about this before.
options as you suggest, config, etc), since that's not part of the Theme specification & it's weird it's just there alongside "content" rn.variants, but they're actually super spread out across all the component keys. So I would be super in favor of putting all the component variants inside the variants, so you'd have variants.buttons.cta & variants.badges.outline or whatever. I think this would also be a nicer bridge between using Components & the JSX pragma. Variants right now are I think the most confusing part of Theme UI to understand, & having them in one object would be a great start.scales, I don't have strong feelings about moving them, but I'd default to not, since I don't think their existing top-level spot is especially confusing or weird. If they're the most important, as you mention, I'm cool to have their placement mirror that.So I would be super in favor of putting all the component variants inside the variants, so you'd have variants.buttons.cta & variants.badges.outline or whatever. I think this would also be a nicer bridge between using Components & the JSX pragma.
variant="styles.a" works. I don't think it was planned, but it is actually quite useful.
This is scary, though
const theme = {
colors: {
background: 'blue',
}
}
<Box variant="colors" />
I think we should totally put Theme UI config in a separate object (options as you suggest, config, etc), since that's not part of the Theme specification & it's weird it's just there alongside "content" rn.
Separate object would be IMO the most elegant, but I'd keep them inside theme.options, because it allows to read them on the type level in "strict mode". They could affect how the types work. (e.g. options.strictMode.allowStrings: false or options.strictMode.scales: ['colors', 'space'])
Separate options property would be great!
Most helpful comment
Separate object would be IMO the most elegant, but I'd keep them inside
theme.options, because it allows to read them on the type level in "strict mode". They could affect how the types work. (e.g.options.strictMode.allowStrings: falseoroptions.strictMode.scales: ['colors', 'space'])