MailSlurp logo

blog

Set the same CSS property twice in React

React style props use JavaScript objects, so duplicate keys cannot provide CSS fallbacks. Learn when to use a class, image-set(), or picture instead.

You cannot safely set the same CSS property twice in a React style prop. The prop receives a JavaScript object, and an object can hold only one value for a given key. If you write backgroundImage twice, the later value replaces the earlier one before React can apply either declaration.

The fix depends on what you are trying to achieve. Use a CSS class when you need normal cascade-based fallbacks, one inline value when the style is genuinely dynamic, and <picture> when the image is content rather than decoration.

Why the second inline property wins

This looks a little like two CSS declarations, but it is just an object literal with a duplicate key:

const heroStyle = {
  backgroundImage: 'url("/images/hero.jpg")',
  backgroundImage: 'image-set(url("/images/hero.webp") 1x)',
};

JavaScript keeps the final backgroundImage value. A linter or compiler may warn about the duplicate, but the browser never receives two declarations to compare.

That is different from a stylesheet. CSS deliberately allows repeated declarations so a browser can ignore a value it does not understand and use an earlier one. React's official style documentation describes the prop as a regular JavaScript object and recommends reserving it for values that depend on JavaScript.

Use a class when you need a CSS fallback

Put both declarations in a stylesheet when the cascade is part of the solution:

.hero {
  min-height: 18rem;
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;

  background-image: url("/images/hero.jpg");
  background-image: image-set(
    url("/images/hero.avif") type("image/avif"),
    url("/images/hero.jpg") type("image/jpeg")
  );
}
import "./Hero.css";

export function Hero() {
  return (
    <section className="hero" aria-labelledby="hero-title">
      <h1 id="hero-title">A background that still has a fallback</h1>
    </section>
  );
}

An older browser that cannot parse image-set() can ignore that declaration and retain the preceding JPEG. A supporting browser can choose a compatible source from the set. The MDN image-set() reference includes current syntax and browser-compatibility details.

This is usually the cleanest answer because the styles are static and CSS is doing the job it was designed to do.

Use one inline value for dynamic styles

Inline styles make sense when a value comes from a prop, API response, or user choice:

type PreviewCardProps = {
  imageUrl: string;
  title: string;
};

export function PreviewCard({ imageUrl, title }: PreviewCardProps) {
  return (
    <article
      className="preview-card"
      style={{ backgroundImage: `url("${imageUrl}")` }}
    >
      <h2>{title}</h2>
    </article>
  );
}

There is one backgroundImage key and one value. Keep shared layout, sizing, positioning, and fallback behavior in the class; use the inline prop only for the piece that changes. Only pass a trusted or validated image URL into CSS; arbitrary user text does not belong in a url() value.

If every target browser supports the syntax you need, a single image-set() string can also be an inline value:

const style: React.CSSProperties = {
  backgroundImage:
    'image-set(url("/images/hero.webp") 1x, url("/images/hero@2x.webp") 2x)',
};

That is still one declaration. It does not provide an earlier CSS fallback, so check the browser support required by your application before using it alone.

Prefer picture for meaningful images

A background image is decorative. It does not have alternative text, and assistive technology does not treat it as page content. If the image explains the product, shows a result, or carries information a reader needs, render an image element instead.

export function ResultPreview() {
  return (
    <picture>
      <source
        srcSet="/images/result.avif 1x, /images/result@2x.avif 2x"
        type="image/avif"
      />
      <source
        srcSet="/images/result.webp 1x, /images/result@2x.webp 2x"
        type="image/webp"
      />
      <img
        src="/images/result.jpg"
        width="960"
        height="540"
        alt="Completed email rendering check with no broken links"
      />
    </picture>
  );
}

Replace the example paths with your own generated image variants. This structure gives the browser format and density choices while preserving a dependable <img> fallback, intrinsic dimensions, and useful alternative text.

Approaches that create more trouble

Avoid these workarounds:

  • Silencing the duplicate-key warning. The first object value is still lost.
  • Mutating element.style through a ref just to add a static declaration. It moves ordinary styling into lifecycle code and is easy to forget during server rendering.
  • Injecting a raw style attribute with dangerouslySetInnerHTML. It adds a security-sensitive escape hatch to solve a normal CSS problem.
  • Using a background image for content that needs alternative text or reliable dimensions.

If the fallback must be dynamic as well as cascade-based, generate a class through your styling system or pass a safe custom property into a class designed to consume it. Keep the browser-support rule in CSS rather than rebuilding the cascade in component code.

When the image will appear in an email

React pages and HTML email have different rendering environments. An approach that works in a modern browser may be ignored or rewritten by an email client. Use conservative email markup, provide meaningful image alternatives, and test the delivered message rather than relying on a web preview.

MailSlurp can render a sent email across real client and device profiles with email device previews. For a repeatable pre-send pass, use the email rendering test guide and check links, dark mode, blocked images, and the call to action before the message reaches customers.

A quick decision guide

  • Need two declarations so the browser can fall back? Use a stylesheet and a class.
  • Need one value that changes at runtime? Use the React style prop.
  • Need resolution or format choices for meaningful content? Use <picture> and <img>.
  • Need a decorative responsive background? Use image-set() in CSS and verify your browser targets.
  • Need the same image to survive email clients? Test the delivered email separately.

The important distinction is simple: React's style prop is an object, while a stylesheet is a list of declarations interpreted by the CSS cascade. Pick the one whose behavior matches the job.