React.js styled-components importing images and using them as div background

109.7k Views Asked by At

I am using styled-components and am trying to set a background image like so

const HeaderImage= styled.div`
    background-image: url('../../assets/image.png');
';

I've also tried without the quotes, like so

const HeaderImage= styled.div`
        background-image: url(../../assets/image.png);
 ';

In both cases, I get the same result

http://localhost:3000/assets/image.png Failed to load resource: the server responded with a status of 404 (Not Found)

I am using Richard Kall's react starter

The file is definitely in the specified location.

Am I loading it incorrectly?

I should mention, I'm very new to this (React, and styled-components)

6

There are 6 best solutions below

11
On BEST ANSWER

You should import images in the following manner (assuming that you have webpack configured for importing media assets).

import myImage from '../../assets/image.png';

/* ... */

const HeaderImage = styled.div`
  background-image: url(${myImage});
`;
0
On

You can pass props to a component like this:

 export const ImgTop = styled.div`
        display: block;
        background-image: ${props => `url(${props.background})`};
        background-size: cover;
        
    `
    <ImgTop background={urlimagen}></ImgTop>
1
On

Importing files is one way of doing it as is suggested above, but it isn't the only way.

Here is an alternative solution, referencing file paths, the original way, using a custom express extension to target your dist folder. (Personally I prefer this approach because it keeps the css clean from the jsx and is self readable)

Disclaimer: This solution is for webpack-dev-server for testing, but once the code is deployed, as long as you have generated your assets with your dist folder it will work by default.

Example:

component.tsx

const Button = styled.button`
  background: url('/assets/file.svg');
`

webpack.config.js

const dist = path.resolve(__dirname, 'dist');
{
  devServer: {
    contentBase: dist,
    historyApiFallback: true,
    before: app => {
      app.use('/assets', express.static(path.resolve(dist, '/assets')));
    }
  }
}
0
On

EDIT : this answer was edited after the question title was updated, due to misleading question title.

Using image as background-image CSS property :

import LogoSrc from './assets/logo.png';

/* ... */

const LogoDiv = styled.div`
  background-image: url(${LogoSrc});
  /* width and height should be set otherwise container will have either have them as 0 or grow depending on its contents */
`;

/* ... */

<LogoDiv />

Normal way of importing and using images :

import LogoSrc from './assets/logo.png';

/* ... */

const Logo = styled.img`
    width: 30px;
    height: 30px;
    margin: 15px;
`;

/* ... inside the render or return of your component ... */

<Logo src={LogoSrc} />

EDIT 2: For reference there is another way to use styled-components, mostly used when using components that you already import (i.e. ant-design components of from other component library) or in case of components that don't work using styled._cp_name_ notation.

NOTE: components need to be compatible with styled-components.

Imagine you would export Logo on a file and import it on another component file :

const Logo = styled.img`
    width: 30px;
    height: 30px;
    margin: 15px;
`;

export default Logo;

Then, on the file where you would import it, you could add more styles by :

import Logo from '../components/Logo';

const L = styled(Logo)`
   border: 1px dashed black;
`;

/* ... then inside render or return ... */
<L />
0
On

For those seeking a dynamic solution, you can also make something work with the <img> element. Some psuedo code that could make this possible:


// styles.tsx

import styled from "styled-components";

export const Relative = styled.div`
  position: relative;
`;
//using the img function is no more supported
export const Image = styled.img`
  z-index: 0;
  position: absolute;
  top: 0;
  left: 0;
`;

export const TextInFrontOfImage = styled.p`
  z-index: 1;
`;


// index.tsx

//..

<Relative>
  <Image src={props.url}></Image>
  <TextInFrontOfImage>Lorem Ipsum</TextInFrontOfImage>
</Relative>

Using some combination of position: relative/absolute and z-index you should be able to achieve similar results to the background-image property.

1
On
import logo from 'public/images/logo.jpg';

/* ... */

const HeaderImg = styled.img.attrs({
  src: `${logo}`
})`
width: 50px;
height: 30px;
`;