Skip to content

Repository files navigation

react-x

npm packagebuildnpm downloads

🇺🇸 English version | 🇷🇺 Русская версия

A React extension library that adds convenient syntax for working with CSS classes, styles, and CSS variables directly in JSX.


💎 Features

  • 🎨 Conditional CSS classes — add classes via class:className with CSS Modules support
  • 💅 Inline styles as props — set styles via style:property
  • 🔧 CSS variables — pass CSS custom properties via var:variableName
  • 📋 classList — array of classes instead of string concatenation
  • 🏷️ All HTML/SVG tags — ready-to-use components x.div, x.span, x.svg, etc.
  • 🔄 HOC for components — wrap your components with x(Component)
  • 📝 Full TypeScript support — out of the box

📦 Installation

npm install @webeach/react-x

or

pnpm install @webeach/react-x

or

yarn add @webeach/react-x

🚀 Quick Start

import{x}from'@webeach/react-x';functionApp(){constisActive=true;constisDisabled=false;return(<x.divclass:container={true}class:active={isActive}class:disabled={isDisabled}style:padding="20px"style:backgroundColor="#f0f0f0"var:primaryColor="#007bff">
Hello, World!
</x.div>);}

Result in DOM:

<divclass="container active"
style="padding: 20px; background-color: #f0f0f0; --primaryColor: #007bff;"
>
Hello, World!
</div>

🛠 API

The x Object

The main export of the library. Works in two ways:

1. As a collection of extended HTML/SVG tags

import{x}from'@webeach/react-x';// HTML tags<x.div>...</x.div><x.span>...</x.span><x.button>...</x.button><x.input/><x.form>...</x.form>// SVG tags<x.svg>...</x.svg><x.path/><x.circle/><x.rect/>

All standard HTML and SVG tags are supported.

2. As a HOC for wrapping components

import{x}from'@webeach/react-x';// Your componentconstButtonInternal=({ className, style, children, ...props})=>(<buttonclassName={className}style={style}{...props}>{children}</button>);// Extended componentconstButton=x(Button);// Usage<Buttonclass:primaryclass:large={size==='large'}style:borderRadius="8px"var:btnColor="blue">
Click me
</Button>

Conditional CSS Classes: class:

Add CSS classes conditionally via props with the class: prefix.

<x.divclass:visible={isVisible}// added if isVisible === trueclass:hidden={!isVisible}// added if isVisible === falseclass:active={isActive}class:error={hasError}class:my-custom-class// kebab-case is supported>
Content
</x.div>

Supported value types:

  • booleantrue adds the class, false does not
  • string — used as an alias (class name from value, not from key)
  • null | undefined — class is not added

Usage with CSS Modules

Pass a string to use with CSS Modules — the value becomes the class name:

importstylesfrom'./Button.module.css';<x.buttonclass:base={styles.button}// adds class from styles.buttonclass:primary={styles.primary}// adds class from styles.primary class:disabled={isDisabled&&styles.disabled}// conditional>
Click me
</x.button>

If styles.button = "Button_button__x7f2s", the result:

<buttonclass="Button_button__x7f2s Button_primary__a3bc1">
Click me
</button>

Important: When passing a string, the value is used as the class name, not the key after class:.


Class Array: classList

An alternative way to pass multiple classes via an array:

constclasses=['card','card-primary',isLarge&&'card-large'];<x.divclassList={classes}>
Content
</x.div>

Falsy array elements are automatically filtered out.

Can be combined with className and class::

<x.divclassName="base-class"classList={['additional','classes']}class:conditional>
All three methods work together
</x.div>// Result: class="base-class additional classes conditional"

Inline Styles: style:

Set CSS properties directly via props with the style: prefix.

<x.divstyle:display="flex"style:justifyContent="center"style:alignItems="center"style:gap="10px"style:padding="20px"style:backgroundColor="#f5f5f5"style:borderRadius="8px">
Flex container
</x.div>

Advantages:

  • IDE autocompletion for CSS property names
  • Typed values
  • Clean syntax without nested objects

Can be combined with regular style:

<x.divstyle={{margin: '10px'}}style:padding="20px"style:color="red">
Styles are merged
</x.div>

CSS Variables: var:

Pass CSS custom properties (variables) via props with the var: prefix.

<x.divvar:primaryColor="#007bff"var:secondaryColor="#6c757d"var:spacing="16px"var:columns={3}><x.spanstyle:color="var(--primaryColor)">
Text in primary color
</x.span></x.div>

Result in DOM:

<divstyle="--primaryColor: #007bff; --secondaryColor: #6c757d; --spacing: 16px; --columns: 3;"><spanstyle="color: var(--primaryColor);">
Text in primary color
</span></div>

Supported value types:

  • stringvar:color="red"
  • numbervar:columns={3}
  • null — to reset a variable

CSS Variables Typing

You can type available CSS variables for a component:

import{ReactNode}from'react';import{x}from'@webeach/react-x';// Define variable typestypeThemeVars={primaryColor: string;secondaryColor: string;spacing: number;};// Typed componentconstThemedBox=x<{children: ReactNode},ThemeVars>(({ children, className, style })=>(<divclassName={className}style={style}>{children}</div>));// Now IDE suggests available variables<ThemedBoxvar:primaryColor="blue"// ✓ autocompletion worksvar:secondaryColor="gray"// ✓var:spacing={16}// ✓var:unknownVar="value"// ✗ TypeScript error>
Content
</ThemedBox>

📥 Usage Examples

Button with Variants

import{ReactNode}from'react';import{x}from'@webeach/react-x';typeButtonProps={variant?: 'primary'|'secondary'|'danger';size?: 'small'|'medium'|'large';disabled?: boolean;children: ReactNode;};functionButton({ variant ='primary', size ='medium', disabled, children }: ButtonProps){return(<x.buttonclass:btnclass:btn-primary={variant==='primary'}class:btn-secondary={variant==='secondary'}class:btn-danger={variant==='danger'}class:btn-sm={size==='small'}class:btn-lg={size==='large'}class:disabled={disabled}disabled={disabled}>{children}</x.button>);}

Button with CSS Modules

import{ReactNode}from'react';import{x}from'@webeach/react-x';importstylesfrom'./Button.module.css';typeButtonProps={variant?: 'primary'|'secondary';disabled?: boolean;children: ReactNode;};functionButton({ variant ='primary', disabled, children }: ButtonProps){return(<x.buttonclass:base={styles.button}class:variant={variant==='primary' ? styles.primary : styles.secondary}class:disabled={disabled&&styles.disabled}disabled={disabled}>{children}</x.button>);}

Themed Card

import{x}from'@webeach/react-x';functionCard({ title, children, accentColor ='#007bff'}){return(<x.articleclass:cardvar:accentColor={accentColor}style:borderLeft="4px solid var(--accentColor)"style:padding="20px"style:borderRadius="8px"style:boxShadow="0 2px 8px rgb(0 0 0 / 0.1)"><x.h2style:color="var(--accentColor)"style:marginTop="0">{title}</x.h2>{children}</x.article>);}

Responsive Grid

import{x}from'@webeach/react-x';functionGrid({ columns =3, gap ='16px', children }){return(<x.divstyle:display="grid"style:gridTemplateColumns={`repeat(${columns}, 1fr)`}style:gap={gap}>{children}</x.div>);}

SVG Icon

import{x}from'@webeach/react-x';functionIcon({ size =24, color ='currentColor'}){return(<x.svgvar:iconSize={`${size}px`}var:iconColor={color}style:width="var(--iconSize)"style:height="var(--iconSize)"viewBox="0 0 24 24"fill="none"stroke="var(--iconColor)"strokeWidth="2"><x.pathd="M12 2L2 7l10 5 10-5-10-5z"/><x.pathd="M2 17l10 5 10-5"/><x.pathd="M2 12l10 5 10-5"/></x.svg>);}

📐 Exported Types

importtype{XClassProps,XStyleProps,XVarProps}from'@webeach/react-x';
  • XClassProps — types for class:* props
  • XStyleProps — types for style:* props (based on CSSProperties)
  • XVarProps<T> — types for var:* props with optional variable typing

⚖️ Comparison with Alternatives

Featurereact-xclsx/classnamesstyled-components
Conditional classesclass:active={bool}clsx({ active: bool })${bool && 'active'}
CSS Modulesclass:x={styles.class}clsx(styles.class)
Inline stylesstyle:padding="10px"Built-in
CSS variablesvar:color="red"${props => props.color}
TypeScript✅ Full
Runtime overheadMinimalMinimalCSS-in-JS
Bundle size~2KB~1KB~15KB

🧩 Dependencies

This library has no external dependencies (Zero dependencies).


🔖 Releasing a New Version

Releases are handled automatically via semantic-release.

Before publishing a new version, ensure that:

  1. All changes are committed and pushed to the main branch.
  2. Commit messages follow the Conventional Commits format:
    • feat: ... — for new features
    • fix: ... — for bug fixes
    • chore: ..., refactor: ... and other types — as needed
  3. Versioning is determined automatically based on commit types (patch, minor, major).

👨‍💻 Author

Development and maintenance: Ruslan Martynov

If you have suggestions or found a bug, open an issue or submit a pull request.


📄 License

This package is distributed under the MIT License.

About

Extended React JSX syntax for conditional classes, inline styles, and CSS variables

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages