The Journey Begins 🚀
I recently decided to dive into open-source contribution by building something I needed in my day-to-day development: a utility for handling CSS class names that works seamlessly with CSS Modules and React Native styles.
The Problem 🤔
If you've worked with CSS Modules or React Native, you've probably written code like this:
// CSS Modules
className={`${styles.container} ${isActive ? styles.active : ''}`}
// React Native
style={[styles.container, isActive && styles.active]}
While libraries like clsx help with class name construction, they don't directly support style objects. This is where class-glue comes in.
The Solution 💡
class-glue provides a unified API for handling both class names and style objects:
// CSS Modules
import createModuleGlue from 'class-glue/merge-module-strings';
import styles from './Card.module.css';
const clgl = createModuleGlue(styles);
function Card({ isHighlighted }) {
return (
<div className={clgl('card', { cardHighlighted: isHighlighted })}>
{/* Resolves to actual CSS Module classes */}
</div>
);
}
// React Native
import createStyleGlue from 'class-glue/merge-styles';
const styles = {
container: { padding: 16, borderRadius: 8 },
active: { backgroundColor: 'blue' }
};
const clgl = createStyleGlue(styles);
function Card({ isActive }) {
return (
<View style={clgl('container', { active: isActive })}>
{/* Merges styles based on conditions */}
</View>
);
}
Technical Deep Dive 🔍
Installation
You can install using your favourite javascript package manager but for the sake of this post -
npm add class-glue
NPM Link: https://www.npmjs.com/package/class-glue
GitHub Link: https://github.com/shettayyy/class-glue
Modular Architecture
The library is split into focused utilities:
-
class-glue
: Core functionality -
join-strings
: String-only operations -
keys-to-strings
: Object-based class generation -
merge-module-strings
: CSS Modules support -
merge-styles
: Style object handling
Each utility is independent and tree-shakeable, ensuring you only bundle what you use.
Bundle Size Optimization
One interesting learning was that for such a small utility, a bundler wasn't necessary. The raw, minified code was already optimal. The entire package is just 425B gzipped!
Type Safety
TypeScript support was a priority. Here's how we handle type inference:
import type { ClassValue } from 'class-glue';
function Button<T extends string>({ className, variant }: {
className?: ClassValue;
variant?: T;
}) {
// Full type safety and inference
}
Learnings & Insights 📚
Building this package taught me several valuable lessons:
- Less is More: For small utilities, avoiding bundlers can actually lead to smaller package size
- Module Systems: Supporting both CommonJS and ESM requires careful consideration
- NPM Workflow: Understanding pre/post scripts and entry points
- GitHub Features: Branch rulesets, discussions, sponsorship setup
- Documentation: The importance of clear, example-driven docs
Get Involved 🤝
The project is open source and welcomes contributions! You can:
- Star the repository
- Try it out:
npm install class-glue
- Provide feedback
- Contribute code or documentation
GitHub Link: https://github.com/shettayyy/class-glue
Conclusion
What started as a simple utility grew into a learning journey about modern package development. The biggest takeaway? No contribution to open source is too small - you often gain more knowledge than you give.
Top comments (0)