Full CSS support for JSX without compromises, providing scoped component-friendly CSS with server-side rendering support
—
Core CSS-in-JS functionality for writing scoped styles directly in JSX components with full CSS support and automatic scoping.
The fundamental way to add CSS to React components. Styles are automatically scoped to the component using unique class names.
<style jsx>{`/* CSS rules */`}</style>Usage Example:
function Card({ title, children }) {
return (
<div className="card">
<h2>{title}</h2>
<div className="content">{children}</div>
<style jsx>{`
.card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 16px;
margin: 8px;
background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.content {
margin-top: 12px;
line-height: 1.5;
}
h2 {
margin: 0;
color: #333;
font-size: 1.2em;
}
`}</style>
</div>
);
}Apply styles globally across the entire application, bypassing component scoping.
<style jsx global>{`/* Global CSS rules */`}</style>Usage Example:
function App() {
return (
<div>
<h1>My App</h1>
<style jsx global>{`
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: #f5f5f5;
}
* {
box-sizing: border-box;
}
h1, h2, h3 {
color: #2c3e50;
}
`}</style>
</div>
);
}Use JavaScript expressions within CSS for props-based styling and conditional styles.
<style jsx>{`
.element {
property: ${expression};
}
`}</style>Usage Examples:
// Props-based styling
function Button({ size = 'medium', variant = 'primary', disabled, children }) {
const sizes = {
small: { padding: '8px 16px', fontSize: '14px' },
medium: { padding: '12px 24px', fontSize: '16px' },
large: { padding: '16px 32px', fontSize: '18px' }
};
const variants = {
primary: { background: '#007bff', color: 'white' },
secondary: { background: '#6c757d', color: 'white' },
outline: { background: 'transparent', color: '#007bff', border: '1px solid #007bff' }
};
return (
<button disabled={disabled}>
{children}
<style jsx>{`
button {
padding: ${sizes[size].padding};
font-size: ${sizes[size].fontSize};
background: ${disabled ? '#e9ecef' : variants[variant].background};
color: ${disabled ? '#6c757d' : variants[variant].color};
border: ${variants[variant].border || 'none'};
border-radius: 4px;
cursor: ${disabled ? 'not-allowed' : 'pointer'};
transition: all 0.2s ease;
}
button:hover {
opacity: ${disabled ? '1' : '0.9'};
transform: ${disabled ? 'none' : 'translateY(-1px)'};
}
`}</style>
</button>
);
}
// State-based styling
function Toggle({ isOn, onToggle }) {
return (
<div className="toggle" onClick={onToggle}>
<div className="slider" />
<style jsx>{`
.toggle {
width: 60px;
height: 30px;
background: ${isOn ? '#4CAF50' : '#ccc'};
border-radius: 15px;
position: relative;
cursor: pointer;
transition: background 0.3s;
}
.slider {
width: 26px;
height: 26px;
background: white;
border-radius: 50%;
position: absolute;
top: 2px;
left: ${isOn ? '32px' : '2px'};
transition: left 0.3s;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
`}</style>
</div>
);
}Target the component's root element using class names, similar to CSS-in-JS :host selector.
// Root element gets jsx-* class automatically
<div className="root">
<style jsx>{`
.root {
/* styles for root element */
}
`}</style>
</div>Usage Example:
function Modal({ isOpen, onClose, children }) {
if (!isOpen) return null;
return (
<div className="modal-overlay">
<div className="modal">
<button className="close" onClick={onClose}>×</button>
{children}
<style jsx>{`
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal {
background: white;
border-radius: 8px;
padding: 24px;
max-width: 500px;
max-height: 80vh;
overflow-y: auto;
position: relative;
}
.close {
position: absolute;
top: 8px;
right: 12px;
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: #999;
}
.close:hover {
color: #333;
}
`}</style>
</div>
</div>
);
}Use :global() pseudo-selector to target elements without scoping, useful for styling third-party components.
<style jsx>{`
:global(.third-party-class) {
/* unscoped styles */
}
.local-class :global(.nested-global) {
/* mixed scoped and global */
}
`}</style>Usage Example:
import Select from 'react-select';
function CustomSelect({ options, value, onChange }) {
return (
<div className="select-container">
<Select
options={options}
value={value}
onChange={onChange}
className="react-select"
classNamePrefix="react-select"
/>
<style jsx>{`
.select-container {
margin: 16px 0;
}
/* Style react-select components globally */
.select-container :global(.react-select__control) {
border: 2px solid #e1e5e9;
border-radius: 8px;
min-height: 44px;
box-shadow: none;
}
.select-container :global(.react-select__control--is-focused) {
border-color: #007bff;
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
}
.select-container :global(.react-select__option--is-focused) {
background-color: #f8f9fa;
}
.select-container :global(.react-select__option--is-selected) {
background-color: #007bff;
}
`}</style>
</div>
);
}Use constants defined outside component scope for consistent theming and reusable values.
// Constants are treated as static styles (no re-computation)
const theme = { primary: '#007bff', spacing: '16px' };
<style jsx>{`
.element {
color: ${theme.primary};
margin: ${theme.spacing};
}
`}</style>Usage Example:
// theme.js
export const theme = {
colors: {
primary: '#007bff',
secondary: '#6c757d',
success: '#28a745',
danger: '#dc3545',
warning: '#ffc107',
info: '#17a2b8',
light: '#f8f9fa',
dark: '#343a40'
},
spacing: {
xs: '4px',
sm: '8px',
md: '16px',
lg: '24px',
xl: '32px'
},
breakpoints: {
sm: '576px',
md: '768px',
lg: '992px',
xl: '1200px'
}
};
// Component using theme constants
import { theme } from './theme';
function Alert({ type = 'info', children }) {
return (
<div className={`alert alert-${type}`}>
{children}
<style jsx>{`
.alert {
padding: ${theme.spacing.md};
margin: ${theme.spacing.sm} 0;
border: 1px solid transparent;
border-radius: 4px;
}
.alert-primary {
background-color: ${theme.colors.primary}15;
border-color: ${theme.colors.primary}30;
color: ${theme.colors.primary};
}
.alert-success {
background-color: ${theme.colors.success}15;
border-color: ${theme.colors.success}30;
color: ${theme.colors.success};
}
.alert-danger {
background-color: ${theme.colors.danger}15;
border-color: ${theme.colors.danger}30;
color: ${theme.colors.danger};
}
@media (max-width: ${theme.breakpoints.md}) {
.alert {
padding: ${theme.spacing.sm};
margin: ${theme.spacing.xs} 0;
}
}
`}</style>
</div>
);
}Install with Tessl CLI
npx tessl i tessl/npm-styled-jsx