Banner with background image
The same fruit-plant offer as Banner with image, with its deadline, heading, description and link over a full-width raspberry photograph.
Use for one short promotion within a page, with a decorative image filling the section. Choose a hero when the content introduces the whole page.
Build with the LoamUI skill
Already added the LoamUI skill? Copy the prompt below. Your agent will check your project and help complete any missing setup before building.
Use the LoamUI skill to build the “Banner with background image” recipe for my application.
Add your content or describe what you want to change. New to the skill? Add it to your project.
import { useId } from "react";import { Badge, SignpostLink } from "@loamui/core";import "./recipe.css"; export default function Recipe() { const titleId = useId(); return ( <section className="banner-background-image" aria-labelledby={titleId}> <img src="https://picsum.photos/id/429/800/600" srcSet="https://picsum.photos/id/429/400/300 400w, https://picsum.photos/id/429/800/600 800w, https://picsum.photos/id/429/1600/1200 1600w" sizes="auto, 100vw" alt="" width="1600" height="1200" loading="lazy" /> <div className="copy"> <p className="eyebrow"> <Badge.Root> <Badge.Text>Offer</Badge.Text> </Badge.Root> <span>Until 30 November · bare-root season</span> </p> <h2 id={titleId}>Members save 20% on fruit plants</h2> <p className="description"> Apples, pears, plums and soft fruit on local rootstocks, lifted the week they are posted. Order before the end of November and the discount comes off at the basket. </p> <div className="actions"> <SignpostLink href="/catalogue/fruit">See the fruit list</SignpostLink> </div> </div> </section> );}
@scope (.banner-background-image) to ([class*="loam-"]) { @layer loamui.components { :scope { background: var(--loam-color-bg); border: 1px solid var(--loam-color-line); border-radius: var(--loam-radius-xl); color: var(--loam-color-fg); container: banner-background-image / inline-size; display: block grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); isolation: isolate; position: relative; &::before { background: color-mix(in oklch, var(--loam-color-bg) 88%, transparent); border-radius: inherit; content: ""; inset: 0; position: absolute; z-index: -1; } } img { block-size: 100%; border-radius: inherit; inline-size: 100%; inset: 0; object-fit: cover; position: absolute; z-index: -2; } /* The copy is the section's body, not its introduction, so it is a box rather than a <header>. */ .copy { align-content: center; display: block grid; font-size: var(--loam-text-md); gap: var(--loam-space-xs); grid-template-columns: minmax(0, 1fr); overflow-wrap: anywhere; padding: var(--loam-space-l); } h2, p { margin-block: 0; } p.eyebrow { --loam-context: primary; align-items: center; display: block flex; flex-wrap: wrap; font-size: var(--loam-text-sm); gap: var(--loam-space-2xs); } h2 { max-inline-size: 22ch; } p.description { max-inline-size: var(--loam-measure); } div.actions { display: block flex; flex-wrap: wrap; gap: var(--loam-space-xs); } @container banner-background-image (inline-size < 44rem) { .copy { grid-column: 1 / -1; } } @media (forced-colors: active) { :scope { border-color: CanvasText; } img, :scope::before { display: none; } } }}
Use this recipe
Copy Recipe.tsx and recipe.css side by side into a React 19 project. Install @loamui/core and load the core stylesheet at your application root, as shown in the installation guide. The component imports its own stylesheet.
Replace the sample offer, closing date, photograph and destination with your own; use the heading level appropriate to the surrounding page. Keep Badge labels short and put longer details in the adjacent wrapping text. Both banners demonstrate a promotion below the initial viewport: loading="lazy" and sizes="auto, 100vw" let the browser choose a rendition from the rendered image width, with a conservative viewport fallback. For a banner visible on first load, remove lazy loading and auto from sizes; set a layout-appropriate size hint and use high fetch priority only if this is the page’s critical image. Supply appropriately cropped renditions through your own image pipeline. useId only connects each section to its heading; this synchronous component needs no client directive.
Uses
Design decisions
How this recipe answers the two pillars, and how it composes the primitives. These notes explain the design. The included tests cover structure and selected interactions; check contrast, keyboard behaviour and assistive technology support in your application.
- Modern
- A section named by its h2 promotes one destination, and the decorative photograph is an img with empty alt, explicit dimensions and lazy loading for a promotion below the fold. Its stylesheet lives in loamui.components inside a donut scope, measuring the header’s fluid token spacing and type through container queries rather than the viewport: the text takes the leading column of a 3:2 grid from 44rem and fills one column below that, with the photograph covering the whole section. Contextualism carries the rest — the surrounding colour scheme resolves the background, scrim, text and link tokens together, and the eyebrow declares the primary brand context so the offer Badge inherits it without a prop, because a promotion does not imply a warning.
- Accessible
- useId names repeated regions independently. A solid background, full foreground text and an 88% scheme-aware background-token scrim protect the words even if the photograph fails; recheck contrast when changing either. Content determines the height and grows with enlarged text. Focus rings are not clipped. Forced colours remove the decorative image and scrim, leaving system colours and a visible border.
- Composition
- The section owns the photograph and scrim instead of overriding a Card surface; Badge and SignpostLink are composed unchanged, beyond the scope boundary.