next-tailwind-image-sizes
v1.0.0
Published
Generate Next.js Image `sizes` props from Tailwind spacing and max-width classes.
Maintainers
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:
- Horizontal spacing - margin and padding that reduces available width
- Max width constraints - Tailwind's max-width classes
- 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-sizesExamples
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 (likemx-4)paddingX?: number | ResponsiveSpacing- Horizontal padding (likepx-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.25rem4=1rem8=2rem
Since margin and padding affect both sides, the package doubles the values:
marginX: 4=mx-4=1remon each side =2remtotal 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
