
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@ffsm/factory
Advanced tools
A powerful component factory for React that simplifies creation of reusable components with built-in support for composition patterns, conditional rendering, prop management, and TypeScript integration.
@ffsm/factory is a powerful component factory for React that simplifies the creation of reusable components with built-in support for composition patterns, conditional rendering, and prop management.
Note: Additional examples and illustrations will be added in upcoming updates.
@ffsm/factory is a powerful component creation system for React that streamlines how you build, compose,
and manage reusable UI components. Unlike traditional component libraries, factory doesn't impose design opinions
but instead focuses on providing a flexible and type-safe foundation for creating your own component ecosystem.
At its core, @ffsm/factory solves common challenges in component development:
The library comes in two versions:
@ffsm/factory): Core functionality for component creation, styling, and prop management@ffsm/factory/compositor): Extended version with advanced UI patterns like conditional rendering, slots, and empty statesInstalling @ffsm/factory is straightforward with your preferred package manager:
# Using npm
npm install @ffsm/factory
# Using yarn
yarn add @ffsm/factory
# Using pnpm
pnpm add @ffsm/factory
Basic vs. Compositor Installation
@ffsm/factory comes in two versions:
import { factory } from '@ffsm/factory';
# Install both packages for compositor features
npm install @ffsm/factory @ffsm/compositor
import { factory } from '@ffsm/factory/compositor';
TypeScript Support
@ffsm/factory includes built-in TypeScript types - no additional packages required.
Peer Dependencies
Optional Integrations
Choose the installation that matches your requirements - start with the basic package for simple component creation, or include the compositor package for advanced UI patterns.
@ffsm/factory provides a comprehensive set of features to streamline React component development:
The core factory functionality focuses on simplified component creation:
import { factory } from '@ffsm/factory';
// Create a simple button component
const Button = factory<{}>('Button', {
className: 'btn',
as: 'button',
});
// Use it in your app
function App() {
return (
<Button className="btn-primary" onClick={handleClick}>
Click Me
</Button>
);
}
When used with the compositor package, additional UI patterns are available:
import { factory } from '@ffsm/factory/compositor';
// Component that only renders for authenticated users
const ProtectedContent = factory<{}>('ProtectedContent', {
condition: (props) => props.isAuthenticated,
conditionFallback: <LoginPrompt />,
});
// Usage
<ProtectedContent isAuthenticated={user?.authenticated}>
<UserDashboard />
</ProtectedContent>;
Factory components automatically handle:
All these features are designed to work together seamlessly, providing a robust foundation for building React component libraries or design systems.
Getting started with @ffsm/factory is simple and straightforward. The library provides an intuitive API
for creating reusable React components with minimal boilerplate:
import { factory } from '@ffsm/factory';
// Create a simple button component
const Button = factory<{}>('Button', {
className: 'btn',
as: 'button',
});
// Use it in your application
function App() {
return (
<Button className="btn-primary" onClick={() => alert('Clicked!')}>
Click Me
</Button>
);
}
The factory() function takes three parameters:
// Static props initialization
const Card = factory<{}>('Card', {
className: 'card',
as: 'div',
});
// Dynamic props based on component props
const Button = factory<{ variant?: 'primary' | 'secondary' }>(
'Button',
(props) => ({
className: `btn ${props.variant ? `btn-${props.variant}` : ''}`,
as: 'button',
})
);
Factory components behave like standard React components:
// Props are merged with initial props
<Button className="mt-4" onClick={handleClick}>
Submit
</Button>;
// Props can be spread
const buttonProps = { className: 'large', disabled: true };
<Button {...buttonProps}>Cancel</Button>;
// Ref forwarding works automatically
const buttonRef = useRef < HTMLButtonElement > null;
<Button ref={buttonRef}>Focus Me</Button>;
You can specify the element type using the as prop:
// Create a component with default element type
const Text = factory<{}>('Text', {
className: 'text',
});
// Override element type when using the component
<Text as="h1" className="text-xl">Heading</Text>
<Text as="p" className="text-sm">Paragraph</Text>
<Text as="span" className="text-xs">Small text</Text>
Factory components are fully typed with TypeScript, providing excellent autocomplete and type checking:
// Define component-specific props
type ButtonProps = {
variant?: 'primary' | 'secondary' | 'outline';
size?: 'sm' | 'md' | 'lg';
};
// Create type-safe component
const Button = factory<ButtonProps>('Button', (props) => ({
className: `btn btn-${props.variant || 'primary'} btn-${props.size || 'md'}`,
as: 'button',
}));
// Type checking and autocomplete work as expected
<Button
variant="primary" // ✓ Autocomplete for 'primary', 'secondary', 'outline'
size="lg" // ✓ Autocomplete for 'sm', 'md', 'lg'
onClick={() => {}} // ✓ Standard button props available
/>;
These examples demonstrate the foundation of using @ffsm/factory for component creation.
The subsequent sections will explore more advanced patterns and features.
The component factory is the heart of @ffsm/factory, providing a flexible and type-safe way to
create reusable React components. This section explores its capabilities, from basic usage to advanced
configuration options.
Creating Components with Factory
The factory() function streamlines the process of creating React components by handling boilerplate
code and providing a consistent API:
import { factory } from '@ffsm/factory';
// Create a simple button component
const Button = factory<{}>('Button', {
className: 'btn',
as: 'button',
});
// Create a card component
const Card = factory<{}>('Card', {
className: 'card',
});
When you create a component with factory(), it:
One of the most powerful features of the factory is dynamic prop initialization, which allows you to define props based on the component's runtime props:
import { factory } from '@ffsm/factory';
// Button component with variant support
const Button = factory<{
variant?: 'primary' | 'secondary' | 'outline';
size?: 'sm' | 'md' | 'lg';
}>('Button', (props) => ({
className: `
btn
${props.variant ? `btn-${props.variant}` : 'btn-primary'}
${props.size ? `btn-${props.size}` : 'btn-md'}
`,
as: 'button',
}));
// Usage
<Button variant="secondary" size="lg">
Large Secondary Button
</Button>;
This approach enables:
The third parameter to factory() lets you configure how the component handles props:
import { factory } from '@ffsm/factory';
// Create a link component with external link handling
const Link = factory<{
isExternal?: boolean;
}>(
'Link',
{
as: 'a',
className: 'link',
},
{
// Don't forward custom props to the DOM
excludeProps: ['isExternal'],
// Custom template function to add security attributes to external links
template: (Component, props, initProps) => (
<Component
{...props}
target={initProps.isExternal ? '_blank' : undefined}
rel={initProps.isExternal ? 'noopener noreferrer' : undefined}
/>
),
}
);
// Usage
<Link href="https://example.com" isExternal>
External Link
</Link>;
Available Options
The factory accepts several configuration options to customize behavior:
Custom Templates
The template option gives you complete control over how your component renders:
// Create a form field with label and error handling
const FormField = factory<{
label?: string;
error?: string;
}>(
'FormField',
{
as: 'input',
className: 'form-control',
},
{
excludeProps: ['label', 'error'],
template: (Component, props, initProps) => (
<div className="form-group">
{initProps.label && (
<label className="form-label">{initProps.label}</label>
)}
<Component {...props} />
{initProps.error && <div className="form-error">{initProps.error}</div>}
</div>
),
}
);
// Usage
<FormField
label="Email Address"
type="email"
placeholder="your@email.com"
error={errors.email}
/>;
Templates are useful for:
By leveraging the configuration options, you can create highly customized and reusable components while maintaining clean, developer-friendly APIs.
The Compositor integration extends @ffsm/factory with advanced UI patterns leveraging
the @ffsm/compositor package. This powerful combination allows you to create components
with built-in support for conditional rendering, slot-based composition, and empty state handling.
To use the compositor features, you need to install both packages:
# Using npm
npm install @ffsm/factory @ffsm/compositor
# Using yarn
yarn add @ffsm/factory @ffsm/compositor
# Using pnpm
pnpm add @ffsm/factory @ffsm/compositor
Import factory from the compositor subpath to access all the enhanced features:
// Import the compositor-enabled factory
import { factory } from '@ffsm/factory/compositor';
// Create components with advanced composition patterns
const Card = factory<{}>('Card', {
className: 'card',
emptyFallback: <p>No content available</p>,
});
The slot-based composition pattern allows you to render children into designated "slots" within your component, similar to how web components handle content projection:
import { factory } from '@ffsm/factory/compositor';
// Create a dialog with header and content slots
const Dialog = factory<{}>('Dialog', {
className: 'dialog',
asSlot: true,
children: ({ children }) => (
<div className="dialog-container">
<div className="dialog-header"></div>
<div className="dialog-content">{children}</div>
</div>
),
});
// Usage with content projected into the slot
<Dialog>This content will be rendered inside the dialog-content div</Dialog>;
Conditional rendering lets you show or hide components based on specific conditions:
import { factory } from '@ffsm/factory/compositor';
// Component that only renders for authenticated users
const ProtectedContent = factory<{
isAuthenticated: boolean;
}>('ProtectedContent', (props) => ({
condition: props.isAuthenticated,
conditionFallback: <LoginPrompt />,
}));
// Component with async conditions (e.g., permission check)
const AdminPanel = factory<{
userId: string;
}>('AdminPanel', (props) => ({
// Can return a Promise for async checks
condition: async () => {
const permissions = await fetchUserPermissions(props.userId);
return permissions.includes('admin');
},
conditionFallback: <AccessDenied />,
}));
// Usage
<ProtectedContent isAuthenticated={Boolean(user)}>
<UserDashboard />
</ProtectedContent>;
Empty state handling provides fallback content when children are empty or non-existent:
import { factory } from '@ffsm/factory/compositor';
// List with empty state
const UserList = factory<{}>('UserList', {
as: 'ul',
className: 'user-list',
emptyFallback: <p className="empty-message">No users found</p>,
});
// Usage with conditional content
<UserList>
{users.length > 0
? users.map((user) => <li key={user.id}>{user.name}</li>)
: null}
</UserList>;
You can also use the asNode option to only render a component when it has children:
import { factory } from '@ffsm/factory/compositor';
// Section that only renders when it has content
const Section = factory<{}>('Section', {
className: 'section',
asNode: true,
});
// Won't render anything
<Section />
// Will render normally
<Section>
<h2>Section Title</h2>
<p>Content here</p>
</Section>
The real power of compositor integration comes from combining these patterns:
import { factory } from '@ffsm/factory/compositor';
// Data panel component with loading, empty, and error states
const DataPanel = factory<{
isLoading: boolean;
error?: string;
}>('DataPanel', (props) => ({
// Only render when not loading
condition: !props.isLoading,
conditionFallback: <LoadingSpinner />,
// Show error message when there's an error
asSlot: Boolean(props.error),
children: props.error ? (
<div className="error-container">{props.error}</div>
) : undefined,
// When no error but no content, show empty state
emptyFallback: <EmptyState message="No data available" />,
}));
// Usage in a data-fetching scenario
<DataPanel isLoading={loading} error={error}>
{data &&
data.items.map((item) => (
<div key={item.id} className="data-item">
{item.name}
</div>
))}
</DataPanel>;
The compositor integration eliminates the need for repetitive conditional rendering patterns, empty state checks, and nested component structures, resulting in cleaner and more maintainable code.
By leveraging these patterns, you can create sophisticated UI components with minimal code while maintaining a clean, declarative API that's easy for other developers to use.
@ffsm/factory works exceptionally well with Tailwind CSS, allowing you to create reusable
components with consistent styling while maintaining the utility-first approach.
Using factory with Tailwind CSS gives you the best of both worlds: the simplicity of Tailwind's utility classes and the reusability of component abstractions:
import { factory, clsx } from '@ffsm/factory';
// Create a reusable button component with Tailwind classes
export const Button = factory<{
variant?: 'primary' | 'secondary' | 'outline';
size?: 'sm' | 'md' | 'lg';
}>('Button', (props) => ({
as: 'button',
className: clsx(
// Base styles
'font-medium rounded transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2',
// Size variations
props.size === 'sm' && 'px-3 py-1.5 text-sm',
props.size === 'lg' && 'px-5 py-2.5 text-lg',
(!props.size || props.size === 'md') && 'px-4 py-2 text-base',
// Variant styles
props.variant === 'primary' &&
'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500',
props.variant === 'secondary' &&
'bg-gray-600 text-white hover:bg-gray-700 focus:ring-gray-500',
props.variant === 'outline' &&
'border border-gray-300 text-gray-700 hover:bg-gray-50 focus:ring-gray-500',
(!props.variant || props.variant === 'primary') &&
'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500'
),
}));
// Usage
<Button variant="secondary" size="lg" onClick={handleClick}>
Save Changes
</Button>;
You can create complete UI systems by composing factory components with Tailwind classes:
// Card components
export const Card = factory<{}>('Card', {
className: 'bg-white dark:bg-gray-800 rounded-lg shadow overflow-hidden',
});
export const CardHeader = factory<{}>('CardHeader', {
className: 'px-4 py-5 sm:px-6 border-b border-gray-200 dark:border-gray-700',
});
export const CardBody = factory<{}>('CardBody', {
className: 'px-4 py-5 sm:p-6',
});
export const CardFooter = factory<{}>('CardFooter', {
className: 'px-4 py-4 sm:px-6 border-t border-gray-200 dark:border-gray-700',
});
// Form components
export const FormGroup = factory<{}>('FormGroup', {
className: 'mb-4',
});
export const Label = factory<{ required?: boolean }>('Label', (props) => ({
as: 'label',
className: 'block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1',
children: props.children,
}));
export const Input = factory<{
error?: boolean;
}>('Input', (props) => ({
as: 'input',
className: clsx(
'block w-full rounded-md shadow-sm sm:text-sm',
props.error
? 'border-red-300 text-red-900 placeholder-red-300 focus:border-red-500 focus:ring-red-500'
: 'border-gray-300 focus:border-blue-500 focus:ring-blue-500'
),
}));
Using factory with Tailwind provides several advantages:
With Tailwind Plugins
Factory components work seamlessly with Tailwind plugins like @tailwindcss/forms:
export const Select = factory<{
error?: boolean;
}>('Select', (props) => ({
as: 'select',
className: clsx(
'block w-full rounded-md shadow-sm sm:text-sm',
props.error
? 'border-red-300 text-red-900 focus:border-red-500 focus:ring-red-500'
: 'border-gray-300 focus:border-blue-500 focus:ring-blue-500'
),
}));
Advanced Tailwind Integration
For more complex scenarios, you can leverage dynamic props with Tailwind:
import { factory, clsx } from '@ffsm/factory';
// Text component with color, size and weight variants
export const Text = factory<{
color?: 'primary' | 'secondary' | 'error' | 'success';
size?: 'xs' | 'sm' | 'base' | 'lg' | 'xl' | '2xl';
weight?: 'normal' | 'medium' | 'semibold' | 'bold';
}>('Text', (props) => ({
className: clsx(
// Size mapping
props.size === 'xs' && 'text-xs',
props.size === 'sm' && 'text-sm',
props.size === 'base' && 'text-base',
props.size === 'lg' && 'text-lg',
props.size === 'xl' && 'text-xl',
props.size === '2xl' && 'text-2xl',
(!props.size || props.size === 'base') && 'text-base',
// Weight mapping
props.weight === 'normal' && 'font-normal',
props.weight === 'medium' && 'font-medium',
props.weight === 'semibold' && 'font-semibold',
props.weight === 'bold' && 'font-bold',
(!props.weight || props.weight === 'normal') && 'font-normal',
// Color mapping
props.color === 'primary' && 'text-blue-600 dark:text-blue-400',
props.color === 'secondary' && 'text-gray-600 dark:text-gray-400',
props.color === 'error' && 'text-red-600 dark:text-red-400',
props.color === 'success' && 'text-green-600 dark:text-green-400',
(!props.color || props.color === 'primary') &&
'text-gray-900 dark:text-white'
),
}));
// Usage
<Text size="lg" color="error" weight="bold">
Something went wrong!
</Text>;
This approach gives you all the benefits of Tailwind's utility-first approach while providing the abstraction and reusability of a component library.
The core factory function for creating components with standardized patterns and prop handling.
// Basic factory
function factory<
AdditionalProps extends Record<string, any>,
Element extends ElementType = 'div',
>(
displayName: string,
init?: InitialProps<Element, AdditionalProps>,
options?: FactoryOptions<Element, AdditionalProps>
): ForwardRefExoticComponent<
PropsWithoutRef<FactoryProps<Element, AdditionalProps>> &
RefAttributes<Element>
>;
// Compositor-enabled factory
// From '@ffsm/factory/compositor'
function factory<
AdditionalProps extends Record<string, any>,
Element extends ElementType = 'div',
>(
displayName: string,
init?: InitialProps<Element, AdditionalProps>,
options?: CompositorFactoryOptions<Element, AdditionalProps>
): ForwardRefExoticComponent<
PropsWithoutRef<FactoryProps<Element, AdditionalProps>> &
RefAttributes<Element>
>;
Parameters
displayName (string): The display name for the component in React DevToolsinit (optional): Initial props or function that returns props based on component propsoptions (optional): Configuration options for the factory componentReturns
A forward ref React component with the specified props and features.
The second parameter (init) of the factory function can be either an object or a function that returns an object. It accepts the following properties:
| Prop | Type | Description |
|---|---|---|
as | ElementType | The base element type to render (div, button, etc.) |
className | string, (props) => string | Static or dynamic class name |
style | CSSProperties, (props) => CSSProperties | Static or dynamic styles |
children | ReactNode, (props) => ReactNode | Static content or render function |
...props | any | Any additional props to pass to the component |
Usage Examples
Static initialization:
const Card = factory<{}>('Card', {
className: 'card p-4 rounded shadow',
as: 'div',
});
Dynamic initialization:
const Button = factory<{ variant?: 'primary' | 'secondary' }>(
'Button',
(props) => ({
className: `btn ${props.variant ? `btn-${props.variant}` : 'btn-primary'}`,
as: 'button',
})
);
The third parameter (options) allows you to configure advanced behavior of your component:
Basic Factory Options
| Option | Type | Description |
|---|---|---|
excludeProps | Array<string> | Props to exclude from being forwarded to DOM |
shouldForwardProp | (key: keyof Props) => boolean | Custom function to determine if a prop should be forwarded |
template | (Component, props, initProps) => ReactNode | Custom rendering template for the component |
Compositor Factory Options (available in '@ffsm/factory/compositor')
| Option | Type | Description |
|---|---|---|
asSlot | boolean | Enable slot-based composition |
asNode | boolean | Render only when children exist |
asNodeFalsy | boolean | Use strict falsy checking for asNode |
emptyFallback | ReactNode | Content to show when children are empty |
condition | unknown , (props) => unknown | Condition for conditional rendering |
conditionFallback | ReactNode | Content to show when condition is falsy |
conditionFalsy | boolean | Use strict falsy checking for condition |
Usage Examples
Excluding custom props:
const Link = factory<{ isExternal?: boolean }>(
'Link',
{
as: 'a',
className: 'link',
},
{
excludeProps: ['isExternal'],
}
);
Custom template:
const FormField = factory<{ label?: string; error?: string }>(
'FormField',
{
as: 'input',
className: 'form-input',
},
{
excludeProps: ['label', 'error'],
template: (Component, props, initProps) => (
<div className="form-group">
{initProps.label && <label>{initProps.label}</label>}
<Component {...props} />
{initProps.error && <div className="error">{initProps.error}</div>}
</div>
),
}
);
Compositor features:
import { factory } from '@ffsm/factory/compositor';
const ProtectedContent = factory<{ isAdmin: boolean }>(
'ProtectedContent',
{
className: 'protected-content',
},
{
condition: (props) => props.isAdmin,
conditionFallback: <AccessDenied />,
}
);
The package exports several utility types for working with factory components:
| Type | Description |
|---|---|
FactoryProps<Element, AdditionalProps> | Combined props type for factory components |
InitialProps<Element, AdditionalProps> | Type for initial props or props factory function |
FactoryOptions<Element, AdditionalProps> | Type for factory options (basic version) |
MaybeFn<Result, Props> | Type that can be either a value or a function returning it |
ObjectProps | Generic object properties type |
Utility for conditionally joining class names:
import { clsx } from '@ffsm/factory';
const className = clsx(
'base-class',
condition && 'conditional-class',
{ 'object-key': booleanValue },
['array', 'of', 'classes']
);
The @ffsm/factory package includes a comprehensive type system that provides full TypeScript support.
This section explains the key types and how to use them effectively in your components.
FactoryProps<Element, AdditionalProps>
This is the main props type for factory-created components. It combines:
// Example: Creating a button with custom props
type ButtonProps = {
variant: 'primary' | 'secondary';
size: 'sm' | 'md' | 'lg';
};
const Button = factory<ButtonProps, 'button'>('Button', {
className: 'btn',
as: 'button',
});
// Usage with type checking:
<Button
variant="primary" // ✓ Type checked
size="sm" // ✓ Type checked
onClick={() => {}} // ✓ Inherited from 'button' element
invalid={true} // ✗ Type error
/>;
InitialProps<Element, AdditionalProps>
This flexible type represents initial props configuration and can be either:
const Card = factory<{}>('Card', {
className: 'card',
as: 'div',
});
const Button = factory<ButtonProps>('Button', (props) => ({
className: `btn btn-${props.variant} btn-${props.size}`,
as: 'button',
}));
Custom Component Props
Define custom props with full type safety:
interface TabProps {
active?: boolean;
label: string;
index: number;
}
const Tab = factory<TabProps>('Tab', (props) => ({
className: props.active ? 'tab active' : 'tab',
'aria-selected': props.active,
role: 'tab',
as: 'div',
}));
// Usage with TypeScript validation
<Tab
label="Settings" // Required
index={2} // Required
active={true} // Optional
/>;
Element Type Customization
Specify a different base element type:
const NavLink = factory<{}, 'a'>('NavLink', {
className: 'nav-link',
as: 'a',
});
// Usage with anchor-specific props
<NavLink href="/about" target="_blank">
About
</NavLink>;
Type Inference Best Practices
When creating a factory component without additional props, always specify an empty object explicitly:
// Correct approach - explicitly specify empty object
export const FormWrapper = factory<{}>('FormWrapper', {
className: 'w-full',
});
// Not recommended - may cause type inference issues
export const FormContainer = factory('FormContainer', {
className: 'flex w-full border border-white/20 rounded-lg',
});
Conditional Props
Create components with conditional prop requirements:
// Better approach using union types
type DialogProps =
| { title: string; size?: 'sm' | 'md' | 'lg'; closable: true; onClose: () => void }
| { title: string; size?: 'sm' | 'md' | 'lg'; closable?: false; onClose?: never };
const Dialog = factory<DialogProps>('Dialog', {
className: 'dialog',
});
// Usage:
// Valid - onClose is required when closable is true
<Dialog title="Settings" closable={true} onClose={() => setOpen(false)} />
// Valid - onClose is not allowed when closable is false
<Dialog title="Info" closable={false} />
// Invalid - missing onClose
<Dialog title="Error" closable={true} /> // TypeScript error
// Invalid - has onClose when closable is false
<Dialog title="Warning" closable={false} onClose={() => {}} /> // TypeScript error
Component Composition Types
Build complex component hierarchies with composed types:
type CardProps = {
title: string;
elevated?: boolean;
};
type CardImageProps = CardProps & {
imageSrc: string;
imageAlt?: string;
};
const Card = factory<CardProps>('Card', {
className: 'card',
});
const CardWithImage = factory<CardImageProps>('CardWithImage', (props) => ({
className: `card ${props.elevated ? 'elevated' : ''}`,
children: (
<>
<img src={props.imageSrc} alt={props.imageAlt || props.title} />
<h3>{props.title}</h3>
</>
),
}));
The package exports several utility types for advanced use cases:
MaybeFn<Result, Props>: Type for values that can be either direct or function-returnedObjectProps: Generic object properties typeFactoryProps<Element, AdditionalProps>: Combined props for factory componentsFactoryOptions<Element, AdditionalProps>: Options for factory configurationImport these types directly from the package:
import { MaybeFn, ObjectProps, FactoryProps } from '@ffsm/factory';
// Create a type for a component that needs dynamic styling
type DynamicComponent<P = {}> = React.FC<
P & {
styling: MaybeFn<string, P>;
}
>;
By leveraging these type utilities, you can create type-safe component APIs that provide excellent developer experience with autocompletion and type checking.
@ffsm/factory includes several utility functions that help with common component development tasks.
These utilities can be imported directly from the package and used both within factory components
and in your application code.
The package includes a lightweight version of the clsx utility for conditional class name composition, allowing you to combine class names dynamically:
import { clsx } from '@ffsm/factory';
// Basic usage
const className = clsx(
'base-class',
condition && 'conditional-class',
isActive ? 'active' : 'inactive',
{ hidden: isHidden, visible: !isHidden }
);
// Within a factory component
const Button = factory<{
variant?: 'primary' | 'secondary';
size?: 'sm' | 'md' | 'lg';
disabled?: boolean;
}>('Button', (props) => ({
as: 'button',
className: clsx(
'btn',
props.variant && `btn-${props.variant}`,
props.size && `btn-${props.size}`,
props.disabled && 'btn-disabled'
),
}));
The clsx utility supports:
'btn'{ 'btn-primary': isPrimary }['btn', isActive && 'btn-active']condition && [subCondition && 'class']false && 'hidden' results in nothing being addedThis eliminates the need for an additional package for class name management in your projects.
While styled-components focuses on styling with CSS-in-JS, @ffsm/factory provides a more comprehensive
approach to component creation with built-in composition patterns, conditional rendering, and prop management.
Yes, @ffsm/factory works with any React-based UI library. You can wrap components from Material UI, Chakra UI,
or any other library using factory().
Yes, @ffsm/factory is compatible with React Server Components, but be aware that some dynamic features
might need client-side hydration.
The regular factory (import { factory } from '@ffsm/factory') provides core functionality for component creation,
prop forwarding, and templates. The compositor factory (import { factory } from '@ffsm/factory/compositor') adds
support for advanced UI patterns like conditional rendering, slot-based composition, and empty state handling through
integration with @ffsm/compositor.
Use the basic factory when you only need component creation and prop management. Use the compositor factory when you need advanced UI patterns like conditional rendering, slots, or empty state handling. The basic factory has fewer dependencies and a smaller bundle size.
The compositor integration adds a small runtime overhead, but it's negligible for most applications. The benefits
of cleaner code and declarative patterns usually outweigh the minimal performance cost. For performance-critical
scenarios with large lists, consider memoizing components with React.memo.
Yes, when using the compositor features, you need to install both packages:
npm install @ffsm/factory @ffsm/compositor
The basic factory doesn't require the compositor package.
While there are many component libraries and styling solutions available, @ffsm/factory offers unique advantages
that set it apart:
Traditional UI libraries like Material UI, Chakra UI, or Ant Design provide pre-built components with specific
design systems. @ffsm/factory takes a different approach:
Unlike CSS-in-JS libraries like styled-components or emotion, @ffsm/factory:
Headless UI libraries like Radix UI or Headless UI provide unstyled components, but @ffsm/factory:
@ffsm/factory is ideal for teams building custom design systems, developers who need flexibility beyond existing UI libraries,
and projects where component consistency and maintainability are priorities.
@ffsm/factory is designed with performance in mind, but there are some considerations to ensure optimal performance in your applications:
const OptimizedCard = React.memo(factory<CardProps>('Card', {...}));
// Dynamic import of compositor-enabled components
const AdminPanel = lazy(() => import('./AdminPanel'));
@ffsm/factory is designed to work across a wide range of React environments:
@ffsm/compositor: The companion package that provides the advanced composition utilities used by factory's compositor integration. Install this package to use the advanced features like slots, conditional rendering, and empty state handling.These packages are designed to work together to provide a complete solution for building React applications, but each can be used independently according to your specific needs.
FAQs
A powerful component factory for React that simplifies creation of reusable components with built-in support for composition patterns, conditional rendering, prop management, and TypeScript integration.
We found that @ffsm/factory demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.