👀 Our most exciting product launch yet 🚀 Join us May 8th for Sanity Connect

Focal point not respected in NextJS + `@sanity/image-url` setup

13 replies
Last updated: Jan 3, 2022
Hi, I am struggling with an image’s focal point. I am using NextJS +
@sanity/image-url
with the following code:
/* JSX */
// CSS Classes are from <https://tailwindcss.com/docs>
<section className={`w-full h-full absolute flex`}>
 <div id="image" className="w-full flex-1 relative">
  <img
   alt={args.data.metadata.alt}
   src={urlFor(args.data.cover).url()}
   className="w-full h-full"
  />
 </div>
<section/>

/* JS */
function urlFor(image) {
  const builder = imageUrlBuilder(sanity);
  return builder.image(image);
}
But the focal point is not respected, even though other options (like crop) are. Is there something I am doing wrong?

I am not using the
next/image
component because it leads to the same result; I thought a normal
<img />
tag would be more appropriate for the sake of this message.
Jan 2, 2022, 8:28 PM
Hi! Do you mean using the focal point that is set in the studio (hotspot), or passing in as an option with the image builder (i.e.
urlFor(...).focalpoint(0.1, 0.1)
)?
Jan 3, 2022, 3:52 PM
The focal point that is set in the studio, yes 😄
Jan 3, 2022, 3:53 PM
It seems to ignore the focal point set as an option too
Jan 3, 2022, 3:55 PM
From what I understand the focal point would only apply if you let sanity crops the image on its own by setting a height or a width on the url, i.e
urlFor(...).width(200)
... but I think it's complicated if an image also have a crop defined at the same time 🤔
Jan 3, 2022, 4:02 PM
In my case, no crop has been applied explicitly on the editor; sanity's query does however send crop data, so I think it's just activated by default.
I did consider the width too, as I suspected the dynamic sizing of the image was to blame, but it doesn't seem to make any difference (just tested again to be sure).
Jan 3, 2022, 4:08 PM
Changing the side of the image only seems to affect the display quality, the focal point is always the same.
Jan 3, 2022, 4:10 PM
I just wrote a helper function to use with the
objectPosition
property.

export default function getPositionFromHotspot(hotspot) {
  if (!hotspot || !hotspot.x || !hotspot.y) return "center";

  return `${hotspot.x * 100}% ${hotspot.y * 100}%`;
}
and in the Next Image component:

<Image
  src={urlForImage(image).url()}
  alt={ ... }
  sizes={ ... }
  layout="fill"
  objectFit="cover"
  objectPosition={getPositionFromHotspot(image?.hotspot)}
/>
Jan 3, 2022, 4:45 PM
I worked! Thank you
Jan 3, 2022, 4:55 PM
My saviors.I don't understand why this is happening in the first place, though. Should it be considered unexpected behavior?
Jan 3, 2022, 4:55 PM
I shouldn't need to set the
objectPosition
property myself
Jan 3, 2022, 4:56 PM
I did it that way so I wouldn't have to set a specific width. I wanted the image to fill its container.
Jan 3, 2022, 5:02 PM
Yup, but in my case it doesn't work even if i set a predefined height and width.
It should according to
this link.

In order for hotspot/crop processing to be applied, the image record must be supplied, as well as both width and height.
Jan 3, 2022, 5:08 PM
I think I'll investigate more and eventually open an issue if I can replicate the problem.
Thank you guys again for your time
Jan 3, 2022, 5:10 PM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?