[v4] Controls (Button, TextInput, etc.) preset heights / sizes
See original GitHub issueEvergreen is born very implicitly, for example, you can pass a height to a control such as as Button
and it works, since it implements a Box
under the hood. This gives enormous flexibility, as you run into new use case you haven’t encountered yet, you can easily support that use case. Although this was true when Evergreen was born, we have learned much along the way, and common sizes and patterns have become more clear.
Benefits of explicit heights
The benefit of explicit heights for controls is that it’s as explicit as you can get. When you do define presets, rarely do you redefine them later (and if you do, it’s common you will have to do visual QA, so it could be considered a breaking change). I see the main reason for having presets making it easier for individuals to make decisions, instead of having to rely on passing a value and conforming to 4/8px
grid manually.
That’s why we have been thinking of giving a bit more opinion to the sizes and heights of controls.
Option 1: Application Level Control
The easiest solution that wouldn’t require any change in Evergreen is application level control. The names of the sizes is just an example.
import { Button } from 'evergreen-ui'
import { Sizes } from 'constants'
<Button height={Sizes.SMALL} />
<Button height={Sizes.DEFAULT} />
<Button height={Sizes.LARGE} />
Pros
- No change in Evergreen
- Complete control application side
Cons
- How does this work for the default value?
- A lot of overhead to keep importing
Sizes
, and might be tricky
Option 2: Overload the height
property with presets.
With Evergreen v4 we introduced theming. In a lot of cases that means properties can access a theme preset, or simply return the value provided. For example: <Pane background="tint1" />
uses a preset, and <Pane background="white" />
simply is passed straight to the component as white
.
What this could mean for controls is that we allow themed presets:
theme.getControlHeight = heightOrPreset => {
if (preset === 'small') return 24
// In some legacy place we need to be compatible with 30 for whatever reason.
// This is not the case for Segment, but could help other team adopt Evergreen easier.
if (preset === 'legacy') return 30
if (preset === 'default') return 32
if (preset === 'large') return 40
return heightOrPreset
}
While using the component this would work as follows:
<Button height="small" />
<Button height="large" />
// Custom height for a one of situation.
<Button height={20} />
Pros
- Can define heights / sizes on a theme level.
- Flexibility when you need to break out of this.
Cons
- Do you really want to support one-of situations?
- Might need to define a couple of sizes that are required by Evergreen to allow consistency within consumers.
Option 3: Deprecate height
. Embrace size
.
The final option is very much inline with option 2. Excepts deprecates height
completely. You can only add presets defined by the theme.
A. Use strings
<Button size="small" />
<Button size="large" />
Pros
- Simple.
- Inline with other component libraries
Cons
- More prescriptive when there is a requirement for a one-of case.
- Although the theme can support more sizes. It can become less explicit over time: e.g. the infamous
smedium
.
- Although the theme can support more sizes. It can become less explicit over time: e.g. the infamous
- Loses a tiny bit of explicitness.
Opinion: Leaning towards option 3. Embrace size
.
Evergreen is growing up, and we need to make the system more explicit over time. Become more opinionated and get efficiency in return. We embrace size
in other parts of our system. For example for typography. So I wouldn’t mind embracing the size property and deprecating height
altogether for controls. size
also seems more consistent with other systems and will allow us to simplify theming logic a bit as well.
The one thing we have to figure out is the perfect scale for sizes. Here is a brain dumb of values (and what I think when I see them) that could be composed in a system:
Some options to compose a scale
- tiny, very tiny, seems like this should be the smallest?
20
- small, small size, but is the smallest?
24
- compact, compact size, but is the smallest?
24
- default, default size.
32
/36
- medium, medium size, might be confusing when used with
default
.32
/36
/40
- longform, what the hell is this? Potentially for longform forms. More functional than descriptive.
36
- big/large, big size, but is the biggest?
36
/40
/48
Final Proposition
size="small | default | large"
=> 24
, 32
, 36
I think those sizes would work well within the scope of our application at Segment. In our product we rarely go up to 40 for controls. But 36
is useful for longer forms. We also use 28
in some places, but I think we can deprecate those to 32
. This would be the default values supported in the default theme within Evergreen
. Custom themes can still embrace different sizes, or change the meaning of our scale.
Issue Analytics
- State:
- Created 5 years ago
- Comments:6 (4 by maintainers)
Top GitHub Comments
My initial vote goes for Option 2: Overload the height property with presets.
One of the strongest points that Evergreen has is that it’s built on top of ui-box. Knowing that, It gives me confidence that I could customize my component the way I want using the naming convention of all supported CSS properties.
Having defaults and string aliases is also very important for quick prototyping, especially if the defaults are carefully put together that covers most use cases.
I’ve been using Evergreen to prototype an app at work and we are soon pushing it to production. My team was quite surprised how fast I was able to have pixel perfect layout and dashboard. Mostly because of that flexibility that Evergreen has right now. I wouldn’t want to lose that.
I like the idea of using a size prop with a few predefined sizes, but I don’t think this necessarily precludes the use of a height prop.
To overload height and have it alter font sizes, line-heights, padding, and so on, seems a bit confusing and inconsistent. In my mind, height should only alter the height of a button, just as it alters the height of a UI-box. I’d argue the same for input boxes. I’ve actually been composing both buttons and inputs in my code to basically provide a size prop in an effort to ensure I use either 2-3 different sizes.
My bias to using
size
might be a legacy of using other ui libraries like bootstrap in the past, but this familiarity has its advantage too – lots (almost all?) ui libraries use a size prop to denote changes to height, font-size, padding, etc.height
usually only adjusts the height of an element.Ideally you could do something like this:
Height would override the default height of a large button.
Alternatively, you could go all in with composition and do something like this: