Type-safe, theme-aware CSS-in-JS powered by @emotion/react. Apply styles directly as props or use the css prop for
advanced patterns like pseudo-classes, media queries, and animations.
Apply CSS properties directly to components:
import { Button } from '@meonode/ui' Button('Click Me', { backgroundColor: 'tomato', padding: '12px 24px', borderRadius: 8, color: 'white', cursor: 'pointer', })
css PropUse the css prop for complex styling patterns:
import { Div } from '@meonode/ui' Div({ padding: '20px', css: { '&:hover': { transform: 'scale(1.05)', }, '@media (max-width: 768px)': { padding: '12px', }, }, })
Powered by @emotion/react — automatic optimization, vendor prefixing, critical CSS extraction for SSR.
import { Button, Input } from '@meonode/ui' const InteractiveButton = Button('Hover Me', { padding: '14px 28px', backgroundColor: '#3B82F6', color: 'white', borderRadius: '10px', cursor: 'pointer', transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)', css: { '&:hover': { backgroundColor: '#2563EB', transform: 'translateY(-3px)', boxShadow: '0 10px 20px rgba(59, 130, 246, 0.4)', }, '&:active': { transform: 'translateY(-1px)', transition: 'all 0.1s ease', }, '&:focus': { outline: 'none', boxShadow: '0 0 0 4px rgba(59, 130, 246, 0.25)', }, '&:focus-visible': { outline: '2px solid #1D4ED8', outlineOffset: '2px', }, '&:disabled': { backgroundColor: '#9CA3AF', cursor: 'not-allowed', transform: 'none', }, }, }) const SmartInput = Input({ padding: '12px 16px', borderRadius: '8px', border: '2px solid #D1D5DB', css: { '&:focus': { outline: 'none', borderColor: '#3B82F6', boxShadow: '0 0 0 3px rgba(59, 130, 246, 0.1)', }, '&:invalid': { borderColor: '#EF4444', }, '&:valid': { borderColor: '#10B981', }, '&::placeholder': { color: '#9CA3AF', fontSize: '14px', }, }, })
import { Div } from '@meonode/ui' const StyledList = Div({ css: { '& .item:first-of-type': { borderTop: '3px solid #3B82F6', fontWeight: 'bold', }, '& .item:last-of-type': { borderBottom: '3px solid #3B82F6', }, '& .item:nth-of-type(odd)': { backgroundColor: '#F3F4F6', }, '& .item:nth-of-type(even)': { backgroundColor: '#FFFFFF', }, }, })
import { Div, Button } from '@meonode/ui' const DecoratedCard = Div({ position: 'relative', padding: '32px', backgroundColor: 'white', borderRadius: '16px', overflow: 'hidden', css: { '&::before': { content: '""', position: 'absolute', top: 0, left: 0, right: 0, height: '4px', background: 'linear-gradient(90deg, #FF6B6B, #4ECDC4, #45B7D1, #96CEB4)', }, '&::after': { content: '"NEW"', position: 'absolute', top: '16px', right: '16px', backgroundColor: '#EF4444', color: 'white', padding: '4px 8px', borderRadius: '12px', fontSize: '10px', fontWeight: 'bold', }, }, }) const QuoteBlock = Div({ position: 'relative', padding: '24px 48px', backgroundColor: '#F8FAFC', borderLeft: '4px solid #3B82F6', fontStyle: 'italic', css: { '&::before': { content: '"\\201C"', // Left quote position: 'absolute', top: '8px', left: '16px', fontSize: '48px', color: '#3B82F6', opacity: 0.5, }, '&::after': { content: '"\\201D"', // Right quote position: 'absolute', bottom: '8px', right: '16px', fontSize: '48px', color: '#3B82F6', opacity: 0.5, }, }, }) const GlowingButton = Button('Glow Effect', { padding: '12px 24px', backgroundColor: '#6366F1', color: 'white', borderRadius: '8px', position: 'relative', css: { '&::before': { content: '""', position: 'absolute', inset: 0, borderRadius: '8px', background: 'linear-gradient(45deg, #6366F1, #8B5CF6)', filter: 'blur(8px)', opacity: 0, zIndex: -1, transition: 'opacity 0.3s ease', }, '&:hover::before': { opacity: 0.7, }, }, })
import { Column } from '@meonode/ui' const ResponsiveHero = Column({ padding: '40px 20px', textAlign: 'center', css: { // Mobile-first approach fontSize: '16px', // Breakpoints '@media (min-width: 640px)': { padding: '60px 40px', fontSize: '18px', }, '@media (min-width: 768px)': { padding: '80px 60px', fontSize: '20px', }, '@media (min-width: 1024px)': { padding: '100px 80px', fontSize: '22px', }, '@media (min-width: 1280px)': { padding: '120px 100px', fontSize: '24px', }, // Orientation '@media (orientation: landscape)': { flexDirection: 'row', }, '@media (orientation: portrait)': { flexDirection: 'column', }, // High DPI '@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi)': { '& img': { imageRendering: 'crisp-edges', }, }, // User preferences '@media (prefers-color-scheme: dark)': { backgroundColor: '#0F172A', color: '#F1F5F9', }, '@media (prefers-reduced-motion: reduce)': { '& *': { animation: 'none !important', transition: 'none !important', }, }, // Print '@media print': { backgroundColor: 'white !important', color: 'black !important', '& button': { display: 'none', }, }, }, })
import { Div, Button } from '@meonode/ui' const FadeInCard = Div({ padding: '24px', backgroundColor: 'white', borderRadius: '12px', css: { '@keyframes fadeInUp': { '0%': { opacity: 0, transform: 'translateY(40px)', }, '100%': { opacity: 1, transform: 'translateY(0)', }, }, animation: 'fadeInUp 0.8s ease-out', }, }) const PulsingButton = Button('Pulse', { padding: '16px 32px', backgroundColor: '#10B981', color: 'white', borderRadius: '12px', css: { '@keyframes pulse': { '0%, 100%': { transform: 'scale(1)', opacity: 1, }, '50%': { transform: 'scale(1.05)', opacity: 0.8, }, }, animation: 'pulse 2s infinite ease-in-out', '&:hover': { animation: 'none', transform: 'scale(1.1)', }, }, }) const Spinner = Div({ width: '60px', height: '60px', border: '4px solid #E5E7EB', borderTop: '4px solid #3B82F6', borderRadius: '50%', css: { '@keyframes spin': { '0%': { transform: 'rotate(0deg)' }, '100%': { transform: 'rotate(360deg)' }, }, animation: 'spin 1s linear infinite', }, })
import { Div, Row } from '@meonode/ui' const MorphingShape = Div({ width: '120px', height: '120px', css: { '@keyframes morph': { '0%': { borderRadius: '50%', backgroundColor: '#EF4444', transform: 'rotate(0deg) scale(1)', }, '25%': { borderRadius: '25%', backgroundColor: '#F59E0B', transform: 'rotate(90deg) scale(1.2)', }, '50%': { borderRadius: '0%', backgroundColor: '#10B981', transform: 'rotate(180deg) scale(1)', }, '75%': { borderRadius: '25%', backgroundColor: '#3B82F6', transform: 'rotate(270deg) scale(0.8)', }, '100%': { borderRadius: '50%', backgroundColor: '#EF4444', transform: 'rotate(360deg) scale(1)', }, }, animation: 'morph 4s ease-in-out infinite', '&:hover': { animationDuration: '1s', }, }, }) const WaveLoader = Row({ gap: '8px', children: Array.from({ length: 5 }, (_, i) => Div({ key: i, width: '20px', height: '60px', backgroundColor: '#3B82F6', borderRadius: '4px', css: { '@keyframes wave': { '0%, 40%, 100%': { transform: 'scaleY(0.4)' }, '20%': { transform: 'scaleY(1)' }, }, animation: 'wave 1.2s ease-in-out infinite', animationDelay: `${i * 0.1}s`, }, }), ), }) const RippleButton = Button('Ripple', { position: 'relative', padding: '16px 32px', backgroundColor: '#6366F1', color: 'white', borderRadius: '12px', overflow: 'hidden', css: { '&::after': { content: '""', position: 'absolute', top: '50%', left: '50%', width: '0', height: '0', borderRadius: '50%', backgroundColor: 'rgba(255,255,255,0.5)', transform: 'translate(-50%, -50%)', transition: 'all 0.5s ease-out', opacity: 0, }, '&:active::after': { width: '200%', height: '200%', opacity: 1, }, }, })
import { Column } from '@meonode/ui' const AdvancedContainer = Column({ padding: '32px', backgroundColor: '#FFFFFF', borderRadius: '16px', css: { // Direct children '& > *': { marginBottom: '20px', transition: 'all 0.3s ease', }, '& > *:last-child': { marginBottom: 0, }, // All buttons '& button': { fontWeight: '600', textTransform: 'uppercase', letterSpacing: '0.5px', }, '& button:hover': { transform: 'scale(1.03) translateY(-1px)', }, // Attribute selectors '& button[data-variant="primary"]': { backgroundColor: '#3B82F6', color: 'white', }, '& button[data-variant="secondary"]': { backgroundColor: 'transparent', color: '#3B82F6', border: '2px solid #3B82F6', }, '& button[data-variant="danger"]': { backgroundColor: '#EF4444', color: 'white', }, // Typography cascade '& h3': { color: '#1F2937', fontWeight: '700', fontSize: '1.5rem', }, '& p': { color: '#6B7280', lineHeight: '1.6', }, // Adjacent sibling '& h3 + p': { marginTop: '8px', fontSize: '18px', color: '#4B5563', }, // Nth-child patterns '& .item:nth-of-type(odd)': { backgroundColor: '#F3F4F6', transform: 'translateX(8px)', }, '& .item:nth-of-type(even)': { backgroundColor: '#FFFFFF', transform: 'translateX(-8px)', }, '& .item:nth-of-type(3n):hover': { backgroundColor: '#DBEAFE', transform: 'scale(1.02)', }, // Data attributes '& [data-highlight="true"]': { backgroundColor: '#FEF3C7', padding: '12px', borderRadius: '8px', border: '2px solid #F59E0B', fontWeight: 'bold', }, }, })
import { Div, Button, Component } from '@meonode/ui' import { useState } from 'react' const DynamicTheme = Component(() => { const [theme, setTheme] = useState('blue') const themes = { blue: { primary: '#3B82F6', secondary: '#1E40AF', accent: '#93C5FD' }, green: { primary: '#10B981', secondary: '#047857', accent: '#6EE7B7' }, purple: { primary: '#8B5CF6', secondary: '#6D28D9', accent: '#C4B5FD' }, } return Div({ padding: '32px', borderRadius: '16px', css: { // Define CSS variables '--primary-color': themes[theme].primary, '--secondary-color': themes[theme].secondary, '--accent-color': themes[theme].accent, '--shadow-color': `${themes[theme].primary}40`, // Use variables backgroundColor: 'var(--primary-color)', color: 'white', boxShadow: '0 8px 25px var(--shadow-color)', '& h2': { color: 'var(--accent-color)', }, '& button': { backgroundColor: 'var(--secondary-color)', borderRadius: '8px', color: 'white', padding: '10px 20px', cursor: 'pointer', transition: 'all 0.3s ease', }, '& button:hover': { backgroundColor: 'var(--accent-color)', boxShadow: '0 6px 12px var(--shadow-color)', }, // Theme-specific gradients '&[data-theme="blue"]': { background: 'linear-gradient(135deg, var(--primary-color), var(--secondary-color))', }, '&[data-theme="green"]': { background: 'radial-gradient(circle, var(--primary-color), var(--secondary-color))', }, '&[data-theme="purple"]': { background: 'conic-gradient(var(--primary-color), var(--accent-color), var(--secondary-color))', }, }, 'data-theme': theme, children: Object.keys(themes).map(themeName => Button(themeName, { key: themeName, onClick: () => setTheme(themeName), css: { opacity: theme === themeName ? 1 : 0.7, transform: theme === themeName ? 'scale(1.1)' : 'scale(1)', }, }), ), }) })
import { createNode } from '@meonode/ui' const Card = createNode('div', { padding: '24px', backgroundColor: '#FFFFFF', borderRadius: '16px', boxShadow: '0 4px 12px rgba(0,0,0,0.1)', transition: 'transform 0.3s ease-in-out', css: { '&:hover': { transform: 'translateY(-5px)', boxShadow: '0 8px 24px rgba(0,0,0,0.15)', }, }, }) // Usage with override Card({ backgroundColor: '#F3F4F6', // Override default children: 'Card content', })
Direct Props for Simple Styles
Use padding, color, display for declarative styling.
css Prop for Complexity
Reserve for pseudo-classes, media queries, animations, nested selectors.
CSS Variables for Dynamic Theming
Runtime theme switching with CSS custom properties.
Type-Safe Development
Leverage TypeScript autocomplete to prevent CSS syntax errors.
Component Factories for Reusability
Use createNode() for styled component factories with default props.
Q: Can I use CSS preprocessors like Sass?
A: No need. MeoNode's nested object syntax, media queries, and vendor prefixing cover Sass/Less functionality with
better type safety.
Q: How does createNode differ from Component?
A: createNode creates a MeoNode factory function requiring .render(). Component creates a React component. Use
createNode for styled primitives, Component for full React components.
Q: Does the css prop support all Emotion features?
A: Yes. MeoNode's css prop uses @emotion/react directly, supporting all Emotion features including nested selectors,
media queries, keyframes, and CSS custom properties.
On this page