31

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)

Telmo Dias
  • 3,938
  • 2
  • 36
  • 48
vedran
  • 1,145
  • 2
  • 13
  • 19
  • Could you try opening `http://localhost:3000/assets/image.png` in your browser? – Fabian Schultz Dec 27 '16 at 13:51
  • Did you try importing the image For example: import someName from '../../assets/image.png' The 'someName' can be replaced by any name you want – Swapnil Dec 27 '16 at 14:35
  • 1
    it's because your code will execute in browser, not in server, so you cant access your file system from browser. You can use 'file-loader' for webpack or serve a static folder. I think the easiest way it's https://www.npmjs.com/package/file-loader – Oleg Pro Dec 27 '16 at 18:31
  • @FabianSchultz, that didn't work. Image not found. – vedran Dec 28 '16 at 06:16

6 Answers6

70

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});
`;
AndyO
  • 1,512
  • 20
  • 28
Ilja
  • 44,142
  • 92
  • 275
  • 498
  • 5
    I needed to explicitly give the `height` and `width` attributes too. – Isaac Pak Jun 25 '17 at 16:33
  • 1
    @IsaacPak so `background-size` css parameter then? Treat styled component as your normal css basically. – Ilja Jun 26 '17 at 09:24
  • 8
    @Ilja what if you want to import images dynamically? – inker Jul 09 '17 at 19:48
  • @inker as from url? just use url in `background-image` ? Its same as you would with css – Ilja Jul 10 '17 at 09:05
  • What if I'm providing urls as a prop to HeaderImage element in render()? – RegarBoy Jun 27 '18 at 15:41
  • 1
    @developer assuming you pas it like this ` props.someUrl})` – Ilja Oct 13 '18 at 16:11
  • This guy answers after me, copies part of my answer, answers incorrectly and gets the correct answer ??? – Telmo Dias Dec 18 '20 at 22:59
  • @TelmoDias Use case in your answer focuses on styled image component. Question is about using image assets as background image source of a div. Besides importing asset, our answers cover different things. – Ilja Dec 19 '20 at 11:33
  • @Ilja sorry but then you should also update the title of the questions which states nothing about background-images... "importing images in React.js with styled-components" – Telmo Dias Dec 19 '20 at 20:50
  • This works in the case of having css determined at the component level, but what if the css is dynamically generated from elsewhere, and simply added in .elm { ${myDynamicCss}}. Really I want a path solution, that I can reference my dist/ folder as the root path of where my assets sit. – Steve Tomlin Mar 17 '21 at 13:39
  • For production it won't matter because the files will be sitting on the server and can be self referenced but to fix the path with webpack-server instead of importing: devServer: { contentBase: dist, historyApiFallback: true, before: app => { app.use('/assets', express.static(path.resolve(__dirname, 'dist/assets'))); } – Steve Tomlin Mar 17 '21 at 15:34
11

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 />
Telmo Dias
  • 3,938
  • 2
  • 36
  • 48
7
import logo from 'public/images/logo.jpg';

/* ... */

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

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')));
    }
  }
}
Steve Tomlin
  • 3,391
  • 3
  • 31
  • 63
  • Indeed, if you will use "/assets/.." pattern it works in the production, but fails for webpackDevServer.. – evasyuk Dec 12 '21 at 12:38
0

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.

Anthony Avila
  • 311
  • 3
  • 6
0

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>
camille
  • 16,432
  • 18
  • 38
  • 60