Created
May 2, 2025 23:08
-
-
Save stevedya/3123b4555c530a009a5fbcf550cc116a to your computer and use it in GitHub Desktop.
Tailwind 3.4 responsive spacing plugin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Responsive Spacing Plugin | |
* | |
* This plugin generates responsive spacing utility classes for Tailwind CSS based on spacing tokens in the config. | |
* It creates utility classes for padding, margin, and gap with values that adjust based on screen sizes. | |
* | |
* How it works: | |
* - Accepts spacing tokens, which can be a single value or an object representing values for different breakpoints (e.g., 'sm', 'md', 'lg'). | |
* - Generates utility classes for different directions (e.g., padding-left, margin-top) that adapt to the screen size using Tailwind's responsive breakpoints. | |
* | |
* Example classes: .p-scale-sm-4, .m-scale-md-2, .gap-scale-lg the generated classes, simply add them to your HTML elements in the same way you would use any other Tailwind CSS utility class. | |
* | |
* @example | |
* <div class="pt-scale-sm px-scale-lg gap-scale-lg bg-surface"> | |
* <!-- Your content here --> | |
* </div> | |
* | |
* @example plugin usage inside of tailwind.config.js: | |
* responsiveSpacingPlugin({ | |
* addComponents: function() { ... }, | |
* tokens: { | |
* 'scale-0': { | |
* sm: '1rem', | |
* md: '2rem', | |
* lg: '3rem', | |
* }, | |
* 'scale-1': theme('spacing.1'), // Singe values can be used to set all breakpoints at once | |
* // ... more scales | |
* } | |
* }); | |
* | |
* @param {Function} options.addComponents - The function provided by Tailwind CSS to register new CSS classes. | |
* @param {Object} options.tokens - The tokens object that represents different spacing scales. Each key-value pair in the object represents a different spacing scale. Each scale is an object itself, with keys for small, medium, and large screens, and values that are the spacing values for each screen size. | |
* | |
*/ | |
module.exports = function responsiveSpacingPlugin({ addComponents, tokens }) { | |
// Helper function to generate directional classes with responsive breakpoints | |
const generateDirectionalClasses = ( | |
prefix, | |
direction, | |
properties, | |
themeKey, | |
breakpoints, | |
) => { | |
// If a single value is provided, use it for all screen sizes | |
const bps = | |
typeof breakpoints === 'string' || typeof breakpoints === 'number' | |
? { sm: breakpoints, md: breakpoints, lg: breakpoints } | |
: breakpoints; | |
const className = `.${prefix}${direction}-${themeKey}`; | |
// Initialize the styles object with all directions and combine them | |
const styles = { | |
[className]: {}, | |
}; | |
// For the small breakpoint (or default), combine all properties | |
properties.forEach((property) => { | |
if (bps.sm) { | |
styles[className][property] = bps.sm; | |
} | |
}); | |
// Combine properties for the medium breakpoint | |
if (bps.md) { | |
styles[className]['@screen md'] = {}; | |
properties.forEach((property) => { | |
styles[className]['@screen md'][property] = bps.md; | |
}); | |
} | |
// Combine properties for the large breakpoint | |
if (bps.lg) { | |
styles[className]['@screen lg'] = {}; | |
properties.forEach((property) => { | |
styles[className]['@screen lg'][property] = bps.lg; | |
}); | |
} | |
return styles; | |
}; | |
// This function generates classes for padding and margin based on the token set that's defined in tailwind.config.js for the responsiveSpacingPlugin. | |
// in the `directions` array. The generated classes will be a responsive based on the values supplied in the spacing object. | |
const generateClasses = (prefix, tokensList, directions) => { | |
const classes = {}; | |
Object.entries(tokensList).forEach(([themeKey, breakpoints]) => { | |
directions.forEach(({ direction, properties }) => { | |
Object.assign( | |
classes, | |
generateDirectionalClasses( | |
prefix, | |
direction, | |
properties, | |
themeKey, | |
breakpoints, | |
), | |
); | |
}); | |
}); | |
return classes; | |
}; | |
// Generate classes for margin | |
const marginDirections = [ | |
{ direction: '', properties: ['margin'] }, // Full margin | |
{ direction: 'x', properties: [`margin-left`, `margin-right`] }, // Left/Right margin | |
{ direction: 'y', properties: [`margin-top`, `margin-bottom`] }, // Top/Bottom margin | |
{ direction: 't', properties: [`margin-top`] }, // Top margin | |
{ direction: 'b', properties: [`margin-bottom`] }, // Bottom margin | |
{ direction: 'l', properties: [`margin-left`] }, // Left margin | |
{ direction: 'r', properties: [`margin-right`] }, // Right margin | |
]; | |
const marginClasses = generateClasses('m', tokens, marginDirections); | |
// Generate classes for padding | |
const paddingDirections = [ | |
{ direction: '', properties: ['padding'] }, // Full padding | |
{ direction: 'x', properties: [`padding-left`, `padding-right`] }, // Left/Right padding | |
{ direction: 'y', properties: [`padding-top`, `padding-bottom`] }, // Top/Bottom padding | |
{ direction: 't', properties: [`padding-top`] }, // Top padding | |
{ direction: 'b', properties: [`padding-bottom`] }, // Bottom padding | |
{ direction: 'l', properties: [`padding-left`] }, // Left padding | |
{ direction: 'r', properties: [`padding-right`] }, // Right padding | |
]; | |
const paddingClasses = generateClasses('p', tokens, paddingDirections); | |
// Logical properties for padding | |
const logicalPaddingDirections = [ | |
{ direction: 's', properties: ['padding-inline-start'] }, // Start padding | |
{ direction: 'e', properties: ['padding-inline-end'] }, // End padding | |
]; | |
const logicalPaddingClasses = generateClasses( | |
'p', | |
tokens, | |
logicalPaddingDirections, | |
); | |
// Logical properties for margin | |
const logicalMarginDirections = [ | |
{ direction: 's', properties: ['margin-inline-start'] }, // Start margin | |
{ direction: 'e', properties: ['margin-inline-end'] }, // End margin | |
]; | |
const logicalMarginClasses = generateClasses( | |
'm', | |
tokens, | |
logicalMarginDirections, | |
); | |
// Gap directions for gap:, column-gap:, row-gap: | |
const gapDirections = [ | |
{ direction: '', properties: ['gap'] }, // Full gap | |
{ direction: '-x', properties: ['column-gap'] }, // Column gap | |
{ direction: '-y', properties: ['row-gap'] }, // Row | |
]; | |
const gapClasses = generateClasses('gap', tokens, gapDirections); | |
// Add the generated classes to Tailwind | |
addComponents({ | |
...paddingClasses, | |
...marginClasses, | |
...logicalPaddingClasses, | |
...logicalMarginClasses, | |
...gapClasses, | |
}); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment