0

I have a very basic component that displays the Page Header (<h1> tags) and Sub Headers (<h3> tags) so if I want to update any styling or add specific functionality, I can update it in one place.

With this, I'm working on a styled-components, but I'm not able to get it to work. I've taken a look here, which is a great starting example, but I wish it was completed with the full written example so I can see what I'm doing wrong.

I'm trying to get my select tag next to my header tag. I was able to get this to work with just the raw/exact html, but when I try to implement it into a component, I can't seem to get it to work. Any thoughts on what I'm doing wrong? Here is my code:

PageHeaderSubSection.js

import React from 'react'
export default class PageHeaderSubSection extends React.Component {
  render() {
    return (
      <h3 className="header-sub-content header-sub-name">
        {this.props.children}
      </h3>
    )
  }
}

MainPage.js

import React from 'react'
import styled from 'styled-components'
import PageHeader from '../common/page/PageHeader'
import PageHeaderSubSection from '../common/page/PageHeaderSubSection'


const StyledPageHeaderSubSection = styled(PageHeaderSubSection)``

const FormHeaderWithButtonStyle = styled.div`
  ${StyledPageHeaderSubSection} {
    margin: 0;
    display: inline-block;
  }
  select {
  vertical-align: text-bottom;
  }
`

class MainPage extends React.Component {

  render() {
    return (
      <>
        <PageHeader>Main</PageHeader>
        <FormHeaderWithButtonStyle>
          <PageHeaderSubSection>Main Modifiable Data</PageHeaderSubSection>
          <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
          <select className="form-control w-auto" >
            <option key={0} value={0}>None</option>
            <option key={1} value={"Select 1"}>{"Select 1"}</option>
            <option key={2} value={"Select 2"}>{"Select 2"}</option>
            <option key={3} value={"Select 3"}>{"Select 3"}</option>
          </select>
        </FormHeaderWithButtonStyle>
        <MoreDataHere />
      </>
    )
  }
}
  • Why do you want to get `select` next to your header tag? – Yaya Aug 19 '21 at 22:31
  • `h3` is a block element by default. Try setting `display: inline` in the css selector for your `h3` element. https://stackoverflow.com/questions/26166907/text-inline-after-h3/26166981 – rexess Aug 19 '21 at 22:33
  • @YahyaParvar I'm confused, how am I using both CSS and styled-components? What would you recommend I do exactly? – StudiousProgrammer Aug 20 '21 at 10:19
  • @rexessilfie I just want the select within the same "row". I already have the `display: inline` working when I just use `h3`. However, I'm trying to figure out the styled-component to work with components as mentioned with my link in my question. – StudiousProgrammer Aug 20 '21 at 10:21
  • I think I get what you are saying clearer after looking at the example for the link in your question! Potential answer coming right up. – rexess Aug 20 '21 at 16:45

2 Answers2

1

What you are trying to do is to contextually style your component FormHeaderWithButtonStyle if it is a child of PageHeaderSubsection.

There is an example here in styled-components documentation.

Abstracting from the styled-components example, this is the kind of setup you would want to have:

const Parent = styled.div``;

const Child = styled.h3`
  ${Parent} & {
    display: inline-block;
  }
`;

function MyComponent() {
  return (
    <Parent>
      <Child>Hello</Child>
      <span>world</span>
    </Parent>
  );
}

Notes

For this to work, both the parent component and the child component have to be styled-components.

  • In case the component you want to style contextually is a basic React component, extend it as a styled component as done here.

Example

Applied to your specific example, you would want something like this:

// Stubs to replace your imports.
const PageHeader = ({ children }) => <h2>{children}</h2>;
const PageHeaderSubSection = ({ className, children }) => (
  <h3 className={className}>{children}</h3>
); // OR const PageHeaderSubSection = styled.h3``

// Changes start here
const FormHeaderWithButtonStyle = styled.div`
  select {
    vertical-align: text-bottom;
  }
`;

// Extend PageHeaderSubSection and apply a contextual style.
// '${FormHeaderWithButtonStyle} &' will target StyledPageHeaderSubSection that are preceeded by (have a parent of) FormHeaderWithButtonStyle.
// The '&' represents the css class for the current component.
const StyledPageHeaderSubSection = styled(PageHeaderSubSection)`
  ${FormHeaderWithButtonStyle} & {
    margin: 0;
    display: inline-block;
  }
`;

class MainPage extends React.Component {
  render() {
    return (
      <>
        <PageHeader>Main</PageHeader>
        <FormHeaderWithButtonStyle>
          {/** Make sure to use StyledPageHeaderSubSection here so that the contextual style can be applied. */}
          <StyledPageHeaderSubSection>
            Main Modifiable Data
          </StyledPageHeaderSubSection>
          <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
          <select className="form-control w-auto">
            <option key={0} value={0}>
              None
            </option>
            <option key={1} value={"Select 1"}>
              {"Select 1"}
            </option>
            <option key={2} value={"Select 2"}>
              {"Select 2"}
            </option>
            <option key={3} value={"Select 3"}>
              {"Select 3"}
            </option>
          </select>
        </FormHeaderWithButtonStyle>
      </>
    );
  }
}

Link to CodeSandbox.

References:

rexess
  • 729
  • 4
  • 7
  • Finally got some time to look at this. I'm not sure if this is what I'm looking for. My `PageHeaderSubSection` is not a component that is a `styled-component`. It's a class which returns an `

    ` tag. Your example might work if my Component was a `styled-component`, but thats not what I have. Am I missing something?

    – StudiousProgrammer Aug 24 '21 at 17:08
  • 1
    It is in fact possible to extend a non-`styled-component` as a `styled-component`, using the `className` prop as seen [here](https://stackoverflow.com/questions/54113367/extending-styles-with-styled-components-not-working). Doing that should allow you to extend just fine. I will update my answer to work with `PageHeaderSubsection` as a regular react component. – rexess Aug 25 '21 at 08:12
  • This is definitely the right answer! But I'm running into an issue. Your code works (obviously, thanks for the CodeSandbox), but you are using `const` to sub for my imports. When I import my `PageHeaderSubSection` component to your code (just like in my question), the styles aren't working. Any idea why? If you take out your `const PageHeaderSubSection...` and replace it with an import for a class (with the component exactly like PageHeaderSubSection in my question), you'll see the style doesn't get applied for the h3. Do you know why that is working for const and not class imports? – StudiousProgrammer Aug 25 '21 at 13:20
  • I think this should work for your convenience: https://codesandbox.io/s/so-demo-styled-component-refer-to-other-forked-rfyws – StudiousProgrammer Aug 25 '21 at 13:21
  • Oh wait, is this because I do *not* allow for classes to be added to the PageheaderSubSection component like you do to allow for classes to be added to `className`? – StudiousProgrammer Aug 25 '21 at 13:25
  • That was my issue. The moment I include `className={this.props.className}` to my `PageHeaderSubSection` component, it worked immediately. Thank you so much @rexessilfie – StudiousProgrammer Aug 25 '21 at 13:33
0

if you want an h3 component that you can reuse and change in one place why don't you just create a styled one. you could make a styled components page and have all your styled-components in so you can import them to any page.

styled.styles.js

export const styledSubHeader= styled.h3`
margin: 0 ;
display: inline-block;

` 

then import this into your page you want to use it and wrap your content in the tag?

<styledSubHeader> SubHeaderContent </styledSubHeader>

or use it in your Main.js

import React from 'react'
import styled from 'styled-components'
import PageHeader from '../common/page/PageHeader'
import PageHeaderSubSection from '../common/page/PageHeaderSubSection'




const FormHeaderWithButtonStyle = styled.div`
  
`
const styledSubHeader = styled.h3`
margin: 0 ;
display: inline-block;

` 

class MainPage extends React.Component {

  render() {
    return (
      <>
        <PageHeader>Main</PageHeader>
        <FormHeaderWithButtonStyle>
          <styledSubHeader>Main Modifiable Data</styledSubHeader>
          <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
          <select className="form-control w-auto" >
            <option key={0} value={0}>None</option>
            <option key={1} value={"Select 1"}>{"Select 1"}</option>
            <option key={2} value={"Select 2"}>{"Select 2"}</option>
            <option key={3} value={"Select 3"}>{"Select 3"}</option>
          </select>
        </FormHeaderWithButtonStyle>
        <MoreDataHere />
      </>
    )
  }
NoobAndroid
  • 86
  • 4
  • 10
  • In a design sense, this makes more sense to include my `styled-component` to my PageHeaderSubSection component. I won't be able to do this because I don't want all my h3 tags to be `inline-block`s. – StudiousProgrammer Aug 20 '21 at 10:32