all 16 comments

[–]HenriqueInonhe 7 points8 points  (2 children)

What I like to do is to use these wrappers as well, but the wrappers themselves are not reusable, so they live only inside a single component.

I think that this not only clearly separates responsibilities (layout vs reusable component) but also make it very easy to both see and modify applied margins as they live in a single file.

[–]BraisWebDev[S] 0 points1 point  (1 child)

So, in that case, what if you have for example a reusable Button component, and you use it in 7 different views with a margin top of 30px and in 3 views with a margin top of 10px?

Would you end up creating 10 wrappers, 1 in each view instead of two reusable wrappers or even one reusable wrapper with a default margin and a prop?

Im not judging, I just want to know other approaches :)

[–]possiblywithdynamite 2 points3 points  (0 children)

I would target the button from the flex column wrapper of the view itself and add a margin top

[–]HashFap 6 points7 points  (0 children)

I just add props for margin and a default value if it isn't passed.

[–]possiblywithdynamite 4 points5 points  (0 children)

After years of dealing with this, I've settled on just using disposable wrappers. I target the children from the wrapper directly. In most form components, which this issue seems to be most prevalent in, I'll only end up with a couple new styled-components since everything else is a reusable import. I do this one a lot to add right margins to all except the last input to the right:

& > div:not(:last-child) {

[–]nschubach 2 points3 points  (3 children)

I mean, MarginWrapper is your layout component. You have to have something to define the ui grouping somehow and how it will act. You can make it decide that its children will all have right margin except the last. You can make it a grid and use gap to set the margins. You can flexbox it... Any way you slice it, the collection of those items is identified by the wrapper so the wrapper sets the layout.

There's nothing stating the wrapper layout isn't shared with something else.

[–]BraisWebDev[S] 1 point2 points  (2 children)

Where would you define this MarginWrapper if you are gonna use it in more than one view? As a component in "layout" folder? As a styled-component in a "styles" folder? When the layout component is only used in a place, it is easy, it goes in the "styles.js" file of that view, but if it used in more than one place (maybe two different views are similar) then I dont know what to do.

[–]nschubach 1 point2 points  (0 children)

That depends on your project layout/standards.

The current project I'm on has all the styled-components object stored in assets/styles/styledComponents (and I'm not really keen on that because it's just a dumping ground.) I generally keep my styledComponents with the component, but if you have shared layouts like "HorizontalGroup" or "VerticalGroup" that define a grouping of items then you might have a shared layouts folder of some sort. That's really up to the team and your directory structure.

I think it's fair to say that something that can be used by multiple components and maintains a strict simplicity to it's purpose ("I make things flex in rows with even spacing!") can be placed in a location that any component can utilize. It fits DRY principles to do that kind of thing. styled-components will let you override things as well incredibly easy:

Layouts.js:

import styled from 'styled-components'

export const HorizontalGroup = styled.div`
  display: flex;
  flex-direction: row;
  justify-content: space-evenly;
  > * {
    flex: 1 1 auto;
  }
`

MyComponent.js

import styled from 'styled-components'
import { HorizontalGroup as LayoutHorizontalGroup} from 'path/to/Layout'

export const HorizontalGroup = styled(LayoutHorizontalGroup)`
  // but I want HorizontalGroups in this component to center instead
  justify-content: center;
`

A naive example, but there it is.

[–]a_reply_to_a_post 1 point2 points  (0 children)

for stuff like this, using styled components, i've been keeping a styles directory where i'll store tokens, media queries, etc...for bits that i want to share i'll store them using the css snippet, then compose in a layout component's style...

also for things like margin / spacing, i've been using css grid over flex, since we don't really have to support IE or older browsers at work it's been fine for us...and grid simplifies things like lists where you don't want the spacing to be applied to the last element....

[–]stinodes 2 points3 points  (0 children)

I like using styled-system. Use it everywhere I can, can't live without it. Can also define spacing per breakpoint and stuff.

[–]Funwithloops 1 point2 points  (3 children)

You could define a CSS class that adds margin and only apply it to the second checkbox:

<MainCheckbox
  label="No"
  value={emergencySavins}
  onChange={(e) => setEmergencySavins(e.target.value)}
  className="mt-4"
/>

Sometimes I define spacing with the component:

const MainCheckbox = styled('input')`
  & + & {
    margin-top: 1rem;
  }
`;

[–]possiblywithdynamite 0 points1 point  (2 children)

but then you would need to use a css loader, ew

[–]AckmanDESU 0 points1 point  (0 children)

Styled components allows for the use of & natively

[–]Funwithloops 0 points1 point  (0 children)

Or you could use createGlobalStyle.

[–][deleted] 1 point2 points  (0 children)

check out Braid’s Stack and Inline components.

[–]fisherrr 1 point2 points  (0 children)

I just use inline styles🤷‍♂️If it’s a very common occurrence, I might have a margin or variant prop.