@salla.sa/twilight-components-react
v3.0.0-beta.1
Published
React wrapper for Salla Twilight Web Components
Maintainers
Readme
@salla.sa/twilight-components-react
React wrapper for Salla Twilight Web Components with full SSR support.
Installation
npm install @salla.sa/twilight-components-react
# or
pnpm add @salla.sa/twilight-components-reactUsage
Client-Side (CSR)
import { SallaButton, SallaModal, SallaAlert } from '@salla.sa/twilight-components-react';
function App() {
return (
<div>
<SallaButton fill="solid" color="primary">
Click Me
</SallaButton>
<SallaModal isOpen={false}>
Modal Content
</SallaModal>
</div>
);
}Tree-Shaking (Optimized Imports)
The generated components include 'use client' directive for Next.js App Router compatibility. All imports are already optimized for tree-shaking:
// ✅ GOOD: Tree-shaking works automatically
import { SallaButton, SallaModal } from '@salla.sa/twilight-components-react';
// ❌ BAD: Imports everything (avoid this)
import * as Twilight from '@salla.sa/twilight-components-react';Server-Side Rendering (SSR)
1. Next.js Setup
Option A: Using next/dynamic (Recommended)
// components/SallaButton.tsx
import dynamic from 'next/dynamic';
export const SallaButton = dynamic(
() => import('@salla.sa/twilight-components-react').then(mod => mod.SallaButton),
{ ssr: false }
);
// Usage
import { SallaButton } from '@/components/SallaButton';
export default function Page() {
return <SallaButton>Add to Cart</SallaButton>;
}Option B: Using 'use client' Directive (App Router)
// components/SallaProvider.tsx
'use client';
export { SallaButton, SallaModal, SallaAlert } from '@salla.sa/twilight-components-react';
// app/page.tsx (Server Component)
import { SallaButton } from '@/components/SallaProvider';
export default function Page() {
return <SallaButton>Server Rendered Button</SallaButton>;
}Option C: Full Hydration with Stencil Hydrate
// app/layout.tsx or pages/_document.tsx
import { hydrate } from '@salla.sa/twilight-components/hydrate';
// For App Router (layout.tsx)
export default async function RootLayout({ children }) {
// Hydrate on server
return (
<html lang="en">
<head>
<script
dangerouslySetInnerHTML={{
__html: `
import('@salla.sa/twilight-components/hydrate').then(m => m.hydrate());
`
}}
/>
</head>
<body>{children}</body>
</html>
);
}2. Custom SSR Setup
// server.ts
import express from 'express';
import { hydrateToString } from '@salla.sa/twilight-components/hydrate';
const app = express();
app.get('*', async (req, res) => {
const html = `
<!DOCTYPE html>
<html>
<body>
<salla-button>Add to Cart</salla-button>
</body>
</html>
`;
// Hydrate on server
const hydratedHtml = await hydrateToString(html, '/');
res.send(hydratedHtml);
});3. Vite SSR Setup
// entry-server.ts
import { hydrateToString } from '@salla.sa/twilight-components/hydrate';
export async function render(url: string) {
const html = `
<div id="app">
<salla-button>Click Me</salla-button>
</div>
`;
return await hydrateToString(html, url);
}Full SSR Example with Next.js
Step 1: Create Hydration Provider
// providers/SallaProvider.tsx
'use client';
import { useEffect } from 'react';
export function SallaProvider({ children }: { children: React.ReactNode }) {
useEffect(() => {
// Import and hydrate on client
import('@salla.sa/twilight-components/hydrate').then(({ hydrate }) => {
hydrate();
});
}, []);
return <>{children}</>;
}Step 2: Use in Layout
// app/layout.tsx
import { SallaProvider } from '@/providers/SallaProvider';
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<SallaProvider>
{children}
</SallaProvider>
</body>
</html>
);
}Step 3: Use Components
// app/page.tsx
import { SallaButton, SallaProductCard } from '@salla.sa/twilight-components-react';
export default function Home() {
return (
<main>
<SallaButton fill="solid" color="primary">
Add to Cart
</SallaButton>
<SallaProductCard
product-id="123"
show-quick-add
/>
</main>
);
}Avoiding Hydration Mismatches
When using SSR with custom elements, wrap components to avoid hydration errors:
// components/SafeSalla.tsx
'use client';
import { useEffect, useState } from 'react';
import { SallaButton } from '@salla.sa/twilight-components-react';
export function SafeSallaButton(props: any) {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
// Return placeholder during SSR
return <button {...props}>{props.children}</button>;
}
return <SallaButton {...props} />;
}Available Components
All components from @salla.sa/twilight-components are available as React components:
SallaButton- Customizable buttonSallaModal- Modal dialogSallaDrawer- Side drawerSallaAlert- Alert notificationsSallaProductCard- Product card displaySallaCartSummary- Cart summarySallaComments- Comments sectionSallaReviews- Product reviews- And more...
Bundle Optimization
Recommended: Tree-shaking with Individual Imports
// ✅ Best - Tree-shake unused components
import { SallaButton } from '@salla.sa/twilight-components-react';Component Groups (Bundles)
These components are bundled together for better caching:
| Bundle | Components | |--------|------------| | UI Core | salla-button, salla-loading, salla-modal, salla-drawer, salla-accordion, salla-breadcrumb | | Forms | salla-file-upload, salla-datetime-picker, salla-color-picker, salla-conditional-fields, salla-tel-input, salla-quantity-input, salla-booking-field | | Comments | salla-comments, salla-comment-form, salla-comment-item, salla-reviews, salla-reviews-page, salla-reviews-summary, salla-rating-stars, salla-review-card | | Product | salla-add-product-button, salla-product-options, salla-product-availability, salla-quick-buy | | Cart | salla-cart-summary, salla-cart-item-offers | | Alerts | salla-alert, salla-bottom-alert |
TypeScript Support
Full TypeScript support is included:
import type { JSX } from '@salla.sa/twilight-components';
interface ButtonProps extends JSX.SallaButton {
onClick?: () => void;
}Related Packages
@salla.sa/twilight-components- Native web components@salla.sa/twilight-components/hydrate- SSR hydration utilities
