Natalia Davydova
Natalia Davydova

Reputation: 748

React component styles depend on its parent

Sorry if the question is stupid, I'm new to React.

Let's say I have such a component:

import React from 'react';

import Container from '../Miscellaneous/Container/Container'
import MaskedImgBlock from '../MaskedImgBlock/MaskedImgBlock'

import HeaderImg from 'assets/img/header/header-img.jpg'

import styles from './Header.module.scss'

const header = (props) => {

  return(
    <header className={styles.mainHeader}>
      <Container>
        <div className={styles.mainHeader_inner}>

          ... {/* some other code here */}

          <MaskedImgBlock 
            src={HeaderImg}
            alt="Team members photo"/>

        </div>
      </Container>
    </header>
  )
};

export default header;

And I have in it a reusable MaskedImgBlock component:

import React from 'react';

import styles from './MaskedImgBlock.module.scss'

const maskedImgBlock = ({ src, alt }) => {

  return (
    <div className={styles.imgBlock}>
      <div className={styles.imgBlock_clipped}>
        <img className={styles.imgBlock_img}
             src={src}
             alt={alt} />
      </div>
    </div>
)};

export default maskedImgBlock; 

This MaskedImgBlock component I want to use inside multiple components in my app, and it must keep its structure and most of styles, but some styles of it's inner elements must be changed according to the component's position.

For example, when this component is inside Header component, one of its inner divs must have a green background-color, and if it's inside a footer component, other inner div must be of yellow background color.

How can I achieve this effect in the most nice way?

Upvotes: 1

Views: 2212

Answers (2)

goto
goto

Reputation: 4445

Similarly to what's done in the Material-UI framework for React, you could introduce a new prop for the MaskedImgBlock component, like in the following example:

const MaskedImgBlock = ({
  src,
  alt,
  classes = {}
}) => {
  const {
    root = '',
    imgWrapper = '',
    img = '',
  } = classes 
  return (
    <div className={`${styles.imgBlock} ${root}`}
      <div className={`${styles.imgBlock_clipped} ${imgWrapper}`>
        <img className={`${styles.imgBlock_img} ${img}`}></igm>
      </div>
    </div>
  )
}

Then, assuming you want to style root and img, you could do the following:

const Header = (props) => {
  return (
    <header>
      <Container>
        <div>
          <MaskedImgBlock 
            src={HeaderImg}
            alt="Team members photo"
            classes={{ 
              root: styles.mainHeader_maskedImgBlock_root,
              img: styles.mainHeader_maskedImgBlock_img
            }}
          />
        </div>
      </Container>
    </header>
  )
}

Or, if you just want the default styling, you don't pass any extra props to your component:

const Header = (props) => {
  return (
    <header>
      <Container>
        <div>
          <MaskedImgBlock 
            src={HeaderImg}
            alt="Team members photo"
          />
        </div>
      </Container>
    </header>
  )
}

This way, you only pass the classes that you want and everything else will default to existing styles.

Upvotes: 3

vicacid
vicacid

Reputation: 537

How do you define styles for MaskedImgBlock classes in parent components?

You use css modules in MaskedImgBlock, so its class names will be generated according with your style/css/or*other-loader config.

If you need couple different representation - it better to add some prop to MaskedImgBlock component and path it from parent like

import React from 'react';

import Container from '../Miscellaneous/Container/Container'
import MaskedImgBlock from '../MaskedImgBlock/MaskedImgBlock'

import HeaderImg from 'assets/img/header/header-img.jpg'

import styles from './Header.module.scss'

const header = (props) => {

  return(
    <header className={styles.mainHeader}>
      <Container>
        <div className={styles.mainHeader_inner}>

          ... {/* some other code here */}

          <MaskedImgBlock 
            theme={'green'}
            src={HeaderImg}
            alt="Team members photo"/>

        </div>
      </Container>
    </header>
  )
};

export default header;

If you want to customize your MaskedImgBlock component with many styles from different parent compoments - the best approach is adding className (or etc.) prop to your MaskedImgBlock component, where you can pass class name from parent component (like your Header component).

import React from 'react';

import Container from '../Miscellaneous/Container/Container'
import MaskedImgBlock from '../MaskedImgBlock/MaskedImgBlock'

import HeaderImg from 'assets/img/header/header-img.jpg'

import styles from './Header.module.scss'

const header = (props) => {

  return(
    <header className={styles.mainHeader}>
      <Container>
        <div className={styles.mainHeader_inner}>

          ... {/* some other code here */}

          <MaskedImgBlock 
            className={styles.maskedImg}
            src={HeaderImg}
            alt="Team members photo"/>

        </div>
      </Container>
    </header>
  )
};

export default header;

And new MaskedImgBlock

import React from 'react';

import styles from './MaskedImgBlock.module.scss'

const maskedImgBlock = ({ src, alt, className = '' }) => {

  return (
    <div className={`${styles.imgBlock} ${className}`}>
      <div className={styles.imgBlock_clipped}>
        <img className={styles.imgBlock_img}
             src={src}
             alt={alt} />
      </div>
    </div>
)};

export default maskedImgBlock; 

Upvotes: 1

Related Questions