npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

next-tailwind-image-sizes

v1.0.0

Published

Generate Next.js Image `sizes` props from Tailwind spacing and max-width classes.

Readme

next-tailwind-image-sizes

Generate Next.js Image sizes props from Tailwind spacing and max-width classes.

What's this about?

You know how Next.js Image components need a sizes prop to work properly with responsive images? And you know how it's always a pain to figure out what that string should be when you're using Tailwind's spacing and max-width classes?

This tiny package does the math for you.

Instead of manually calculating:

<Image
	src="/hero.jpg"
	sizes="(min-width: 1024px) min(32rem, calc(100vw - 4rem)), calc(100vw - 2rem)"
	// ^ Who wants to figure this out by hand?
/>

You can just:

import { generateSizes } from 'next-tailwind-image-sizes'

const sizes = generateSizes({
  marginX: 4,      // mx-4 (1rem on each side)
  paddingX: { md: 6 }, // px-6 from md breakpoint up
  maxWidth: 'lg'   // max-w-lg (32rem)
})

<Image src="/hero.jpg" sizes={sizes} />

First implementation

This is my first attempt at this and I'm not 100% sure it works in all cases. I've tested the basic scenarios but responsive images are tricky. If you find issues, please let me know!

The API is pretty basic right now - it only handles horizontal margin/padding (mx-* and px-* classes), not the individual sides or vertical spacing.

How it works

The package calculates the available width for your image based on:

  1. Horizontal spacing - margin and padding that reduces available width
  2. Max width constraints - Tailwind's max-width classes
  3. Responsive breakpoints - Different spacing at different screen sizes

It follows Tailwind's mobile-first approach where styles cascade upward through breakpoints.

Installation

npm install next-tailwind-image-sizes
# or
pnpm add next-tailwind-image-sizes

Examples

Simple max-width only

<Image
	src="/hero.jpg"
	alt="Hero image"
	sizes={generateSizes({ maxWidth: 'lg' })}
	// → "32rem"
/>

Just spacing

<Image
  src="/content.jpg"
  alt="Content image"
  sizes={generateSizes({ marginX: 4 })}
  // → "calc(100vw - 2rem)"
/>

<Image
  src="/article.jpg"
  alt="Article image"
  sizes={generateSizes({ paddingX: 2 })}
  // → "calc(100vw - 1rem)"
/>

Max-width with spacing

<Image
	src="/card.jpg"
	alt="Card image"
	sizes={generateSizes({
		marginX: 2,
		paddingX: 2,
		maxWidth: 'lg',
	})}
	// → "min(32rem, calc(100vw - 2rem))"
/>

Responsive spacing

generateSizes({
	marginX: 2,
	paddingX: { sm: 4 }, // No padding on mobile, px-4 from sm up
	maxWidth: 'full',
});
// → "(min-width: 640px) calc(100vw - 3rem), calc(100vw - 1rem)"

Complex responsive layout

generateSizes({
	marginX: {
		default: 4, // mx-4 on mobile
		lg: 8, // mx-8 from lg breakpoint up
	},
	paddingX: 6, // px-6 on all breakpoints
	maxWidth: '4xl',
});
// → "(min-width: 1024px) min(56rem, calc(100vw - 7rem)), min(56rem, calc(100vw - 5rem))"

Percentage-based max-widths

generateSizes({
	marginX: 4,
	maxWidth: '1/2', // 50% width
});
// → "min(50%, calc(100vw - 2rem))"

API

generateSizes(options)

Options:

  • marginX?: number | ResponsiveSpacing - Horizontal margin (like mx-4)
  • paddingX?: number | ResponsiveSpacing - Horizontal padding (like px-6)
  • maxWidth?: MaxWidthValue - Max width constraint

ResponsiveSpacing:

{
  default?: number  // Base mobile value
  sm?: number      // 640px+
  md?: number      // 768px+
  lg?: number      // 1024px+
  xl?: number      // 1280px+
  '2xl'?: number   // 1536px+
}

MaxWidthValue:

  • Size names: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | '7xl'
  • Screen sizes: 'screen-sm' | 'screen-md' | 'screen-lg' | 'screen-xl' | 'screen-2xl'
  • Fractions: '1/2' | '1/3' | '2/3' | '1/4' | '3/4' | '1/5' | '2/5' | '3/5' | '4/5' | '1/6' | '5/6'
  • Special: 'full'

How spacing works

Tailwind spacing values map to rem:

  • 1 = 0.25rem
  • 4 = 1rem
  • 8 = 2rem

Since margin and padding affect both sides, the package doubles the values:

  • marginX: 4 = mx-4 = 1rem on each side = 2rem total horizontal space

Responsive behavior explained

When you use responsive spacing, it follows Tailwind's mobile-first cascade:

paddingX: {
  default: 2,  // px-2 on mobile (0.5rem each side = 1rem total)
  md: 6        // px-6 from md up (1.5rem each side = 3rem total)
}

This generates media queries that apply the larger padding at the md breakpoint and above, falling back to the default on smaller screens.

If you don't specify default, it assumes no spacing on mobile (like how md:px-6 works in Tailwind).

Real-world usage

// Hero section with responsive container
const heroSizes = generateSizes({
	marginX: { default: 4, lg: 8 },
	maxWidth: '6xl',
});

// Card in a grid with consistent padding
const cardSizes = generateSizes({
	paddingX: 6,
	maxWidth: 'sm',
});

// Full-width with mobile margins
const fullWidthSizes = generateSizes({
	marginX: 4,
	maxWidth: 'full',
});

Contributing

Found a bug? Got an idea? This is still pretty experimental so I'd love feedback! Open an issue or PR.

License

MIT