CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-styled-jsx

Full CSS support for JSX without compromises, providing scoped component-friendly CSS with server-side rendering support

Pending
Overview
Eval results
Files

component-styling.mddocs/

Component Styling

Core CSS-in-JS functionality for writing scoped styles directly in JSX components with full CSS support and automatic scoping.

Capabilities

Basic Scoped Styles

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>
  );
}

Global Styles

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>
  );
}

Dynamic Styles

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>
  );
}

Targeting Root Element

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>
  );
}

One-off Global Selectors

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>
  );
}

Constants and External Values

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

docs

babel-macro.md

build-integration.md

component-styling.md

external-css.md

index.md

style-registry.md

tile.json