Recompose: ButtonGroup - When nesting affects Style

Phil Holden
InstructorPhil Holden

Share this video with your friends

Send Tweet
Published 6 years ago
Updated 3 years ago

In CSS we use the descendant selector to style elements based on their nesting. Thankfully in React we don't need to consider this most of the time because this nesting of elements happens within the bounds of a single component.

However occasionally the nesting of components affects the styles. In these rare cases we can use context to influence styles yielding a user friendly api to our components.

[00:00] Next in our theming with React and Recompose adventure, we're going to look at the example of button groups. The interesting thing about button groups is that a button changes the way it displays itself, by virtue of the fact that it happens to be in a button group.

[00:14] You can see that the button on the left is slightly different to the button in the middle and the button on the right. If I was to move this button out of the button group, it would appear with rounded corners on all sides.

[00:24] This is, of course, using the CSS descendant selector. That's when you place a space between two classes within your CSS, and then you can make something behave differently according to nesting.

[00:36] However, when we use inline styles and place our styles inside the component, this is impossible to do, because we have style isolation. How can the component know about its context?

[00:47] Ah, context. For the sake of this example, we're going to try and create a mobile style button group, and that's like a button bar that might sit at the bottom of your app. We're going to use Flexbox for this layout, which means that the button group is going to be kind of this outer box here, and it's going to have some marginal padding, which is going to be this distance between here and here.

[01:08] Then the buttons themselves are going to have some margin on them, and that's going to mean that the distance between here and here is going to be equal to the distance between here and here.

[01:22] When a button appears in the context of a button group, it's going to have this margin here, and when it appears outside of the context of the button group, it's not going to have this margin.

[01:31] I'm back in my Recompose Theme project, and I'm in the file that defines my theme variables. I'm going to add a theme variable called Button Group Space, and this is going to determine the space between my buttons in my button group.

[01:45] I'm in my app.js file, and it's here that I define my theme editor as a series of inputs for editing my theme variables. I'm going to add an input for my Button Group Space. I'm going to copy this here, and paste it, and I'm going to change this button radius here to Button Group Space.

[02:07] I'm going to create a Button Group component. We'll start with a fairly plain component, Import React, and then we separate out the children from the rest of the props, and we spread the rest of the props onto a Div, and we put the children in the Children part of this Div.

[02:28] Then we export the Button Group as before. We're going to enhance this component using Recompose. I'm going to import Compose, Set Display Name, and With Context. We want to use the Context in order to parse down, like a Button Group Context, to any buttons that might be inside this Button Group.

[02:46] In order to do that, I'm going to need the Prop Types from React, and also, I'm going to import HOC functions that we created ourselves in previous videos, so Get Theme, Add Style, and Theme Style.

[03:00] Let's create our enhanced function, and to start with, we're going to set the display name. This is useful for debugging. Let's enhance our button group. First we use our Add Style, Higher Order Component to set some default styles. I'm going to set the margin to be six. We'll override this later with our Map Theme to Style function, and the display to be Flex. We'll be using Flexbox.

[03:19] We're going to add With Context on to our Compose Stack, and we're going to set a Context Property called Button Group. This is always going to be a type Bullion, and is always going to return the value True.

[03:30] We've got a function here, and it's just always returned Button Group as True. What that means is that whenever a child is within a Button Group component, then on the Context Button Group, it's going to be true.

[03:44] We also want this margin size here to respond to the Button Group spacing here. I'm going to have to add in my Get Theme from the Context, and then also use this theme style, High Order Component, to map the theme onto a style so that we can override this default margin size here.

[04:11] I've added in my Map theme to Style Function, and I'm destructuring Number off of our theme variables, because the Button Group spacing was kind of Number, Adult Button Group Spacing. I'm just casting this string to an int by multiplying it by one, and I'm setting the margin and the style now to be whatever is coming off the Number Button Group space.

[04:34] Map Theme to Style actually takes in a second argument, and that's the props, and so I'm going to destructure Is Vertical off the props. This allows us to make a decision on the Button Group, whether the flex direction will be column, or the flex direction will be row, based on whether it is vertical is true or false.

[04:56] This should be a single dot here, and I need to import Radium, and then put this at the bottom of my enhanced stack. Now, my Higher Order Components file, my HOCs file, and I'm going to copy this and paste it. I'm going to create a Get Button Group.

[05:18] We are going to get Button Group off here, and it is a billion. This gets the Button Group off the Context. Now I'm back in my Button Component file, and I'm going to add in my Higher Order Component for getting the Button Group off the Context.

[05:41] Next, I'm going to want to add my Get Button Group on to my enhanced [indecipherable] , put this in here, underneath Get Theme, and this is going to put Button Group onto the props, so I can then pull it off the props on my Map Theme to Style Function, and that takes a second argument.

[06:00] I can destructure it off the props here, and then I can add in another conditional assignment here, and say, "If Button Group is truthy, then set the margin to be the Button Group spacing," which we're bringing off the theme variables, and then casting that to an int, and now I can go back into my app.js and have a go at adding in a button group.

[06:31] We've got a problem here, because we're not getting the gap we're expecting around these buttons. I'm going to try and see where that is. If I go into my button file, and I'm adding in the margin as I expect, I've got my HOCs the wrong way around.

[06:47] I need Get Button Group to be above the Theme Style, because Theme Style is using the Button Group prop. I'm going to save that. Something still looks a bit off, so I'm going back into my app.js and I am going to add a surrounding Div just with some white background.

[07:07] I'm going to change the margin on the Button Group into padding just to make it a bit clearer. Now you can see, I've got consistent margining and padding all the around my buttons.

[07:17] I'm going to click in here, and have a go at editing it. I can change it like this. It's kind of cool. Let's try 20, 10. Now let's try adding another button in. I'm going to take this and copy, paste, and now let's try setting Button Group is Vertical, and let's try changing this.

[07:55] In conclusion, in CSS, we use the descendant selector to style elements based on their nesting. Thankfully, in React, we don't need to consider this most of the time, because the nesting of elements happens within the bounds of a single component.

[08:08] However, occasionally the nesting of components within other components can affect the styles of the child. In these rare cases, we can use Context to apply styles that are dependent on nesting, yielding a user-friendly API to our UI library.

Zhentian Wan
Zhentian Wan
~ 5 years ago

Like recompose lessons. Waiting for mooooore :D