JavaScript Styling#
Inline styles using JavaScript objects for dynamic styling in Jac applications.
Overview#
JavaScript styling uses JavaScript objects to define styles, which are then applied via the style prop. This approach is perfect for:
- Dynamic styling based on state
- Programmatic style generation
- Component-scoped styles without CSS files
- React-style inline styling
Example#
See the complete working example: examples/css-styling/js-styling/
Quick Start#
1. Define Style Objects#
Create styles.js:
const countDisplay = {
fontSize: "3.75rem",
fontWeight: "bold",
transition: "color 0.3s ease"
};
export default {
container: {
minHeight: "100vh",
background: "linear-gradient(to bottom right, #dbeafe, #e0e7ff)",
display: "flex",
alignItems: "center",
justifyContent: "center",
padding: "1rem"
},
card: {
backgroundColor: "#ffffff",
borderRadius: "1rem",
boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
padding: "2rem",
maxWidth: "28rem",
width: "100%"
},
countDisplayZero: {
...countDisplay,
color: "#1f2937"
},
countDisplayPositive: {
...countDisplay,
color: "#16a34a"
},
countDisplayNegative: {
...countDisplay,
color: "#dc2626"
},
button: {
color: "#ffffff",
fontWeight: "bold",
padding: "0.75rem 1.5rem",
borderRadius: "0.5rem",
border: "none",
cursor: "pointer"
},
buttonDecrement: {
backgroundColor: "#ef4444"
},
buttonReset: {
backgroundColor: "#6b7280"
},
buttonIncrement: {
backgroundColor: "#22c55e"
}
};
2. Import Styles#
# Pages
cl import from react {useState, useEffect}
cl import from .styles { default as styles }
cl {
def app() -> any {
return <div style={styles.container}>
<div style={styles.card}>
<h1 style={styles.title}>Counter Application</h1>
</div>
</div>;
}
}
3. Apply Styles#
Use the style prop with style objects:
return <div style={styles.container}>
<div style={styles.card}>
<h1 style={styles.title}>Counter Application</h1>
</div>
</div>;
4. Dynamic Styles#
Select styles based on state:
let countStyle = styles.countDisplayZero if count == 0 else (styles.countDisplayPositive if count > 0 else styles.countDisplayNegative);
return <div style={countStyle}>{count}</div>;
Style Object Format#
JavaScript style objects use camelCase property names (React convention):
{
backgroundColor: "#ffffff", // not background-color
fontSize: "1.5rem", // not font-size
marginTop: "10px", // not margin-top
zIndex: 1, // not z-index
borderTopLeftRadius: "4px" // not border-top-left-radius
}
Best Practices#
1. Use Object Spread#
Share common styles with spread operator:
const baseButton = {
padding: "0.75rem 1.5rem",
borderRadius: "0.5rem",
border: "none",
cursor: "pointer"
};
export default {
primaryButton: {
...baseButton,
backgroundColor: "#007bff",
color: "#ffffff"
},
secondaryButton: {
...baseButton,
backgroundColor: "#6c757d",
color: "#ffffff"
}
};
2. Organize by Component#
Group related styles together:
export default {
// Container styles
container: { ... },
card: { ... },
// Button styles
button: { ... },
buttonPrimary: { ... },
buttonSecondary: { ... },
// Text styles
title: { ... },
subtitle: { ... }
};
3. Use Constants#
Define reusable values at the top:
const COLORS = {
primary: "#007bff",
secondary: "#6c757d",
success: "#28a745",
danger: "#dc3545"
};
const SPACING = {
sm: "0.5rem",
md: "1rem",
lg: "2rem"
};
export default {
button: {
backgroundColor: COLORS.primary,
padding: SPACING.md
}
};
4. CamelCase Properties#
Follow React naming convention:
// Good
{
backgroundColor: "#fff",
fontSize: "1rem",
marginTop: "10px"
}
// Avoid
{
"background-color": "#fff", // Wrong
"font-size": "1rem" // Wrong
}
5. Extract Complex Logic#
Move style calculations to functions:
export const getButtonStyle = (variant, disabled) => {
const base = {
padding: "0.75rem 1.5rem",
borderRadius: "0.5rem",
border: "none",
cursor: disabled ? "not-allowed" : "pointer",
opacity: disabled ? 0.5 : 1
};
const variants = {
primary: { backgroundColor: "#007bff", color: "#ffffff" },
secondary: { backgroundColor: "#6c757d", color: "#ffffff" }
};
return { ...base, ...variants[variant] };
};
Advanced Patterns#
Style Functions#
Create functions that return styles:
export const getButtonStyle = (variant) => ({
padding: "0.75rem 1.5rem",
borderRadius: "0.5rem",
backgroundColor: variant === 'primary' ? '#007bff' : '#6c757d',
color: '#ffffff'
});
Use in Jac:
Conditional Styles#
Use ternary operators for conditional styles:
export default {
button: (isActive, isDisabled) => ({
backgroundColor: isActive ? '#007bff' : '#6c757d',
opacity: isDisabled ? 0.5 : 1,
cursor: isDisabled ? 'not-allowed' : 'pointer'
})
};
Dynamic Values#
Calculate styles based on props:
export const getContainerStyle = (width, height) => ({
width: `${width}px`,
height: `${height}px`,
display: "flex",
alignItems: "center",
justifyContent: "center"
});
Advantages#
- Dynamic styling based on props/state
- No CSS file needed
- Type-safe with TypeScript
- Component-scoped by default
- Programmatic style generation
- Easy to debug (JavaScript objects)
- No build step for styles
Limitations#
- No pseudo-classes (hover, focus, etc.)
- No media queries
- No CSS animations (use JavaScript)
- Verbose for complex styles
- No CSS preprocessor features
- Performance can be slower for many elements
When to Use#
Choose JavaScript Styling when:
- You need dynamic styles based on state
- You want programmatic style generation
- You prefer keeping styles in JavaScript
- You're building component libraries
- You need runtime style calculations
- You want type safety with TypeScript
Import Syntax#
Style objects are imported as JavaScript modules:
# Default export
cl import from .styles { default as styles }
# Named exports (if using named exports)
cl import from .styles { button, card, container }
Combining Styles#
You can combine multiple style objects:
let combinedStyle = {
...styles.base,
...styles.button,
...(isActive ? styles.active : {})
};
return <button style={combinedStyle}>Click Me</button>;
Next Steps#
- Explore Styled Components for CSS-in-JS with more features
- Check out Emotion for similar CSS-in-JS approach (coming soon)
- Learn about CSS Modules for scoped CSS (coming soon)
- See Pure CSS for traditional CSS approach