Skip to main content

Getting Started

Welcome to Haus Tech's headless storefront ecosystem! This guide will help you get up and running with our components, libraries, and tools.

Overview​

Haus Storefront Components is a collection of headless, cross-platform React components and hooks designed for building e-commerce storefronts. The library is organized into several categories:

  • Core Libraries: Foundation functionality including SDKs, providers, and data management
  • Common Libraries: Shared utilities, hooks, and UI components
  • Store Components: E-commerce specific components (cart, product list, checkout, etc.)
  • Plugin Configurations: Platform integrations and extensions

Prerequisites​

Before you begin, make sure you have:

  • Node.js version 18 or higher
  • React 19 or higher
  • TypeScript (recommended for type safety)
  • Access to Haus Tech's private npm registry (contact the Haus Tech Team for access)
  • A Vendure backend API endpoint (Vendure is our default provider - see Vendure Integration for details)

Quick Start​

1. Install Core and Providers​

Install @haus-storefront-react/core and @haus-storefront-react/providers. Core supplies DataProvider, SDKs, and hooks; the providers package includes the Vendure preset builder.

npm install @haus-storefront-react/core @haus-storefront-react/providers

Note: The packages are not publicly available. Contact the Haus Tech Team for access to the private npm registry.

2. Set Up the DataProvider​

Wrap your application with DataProvider and a Vendure preset. This wires the SDK, query client, interceptors, and platform detection to all child components.

import { DataProvider } from '@haus-storefront-react/core'
import { VendureProviderPreset } from '@haus-storefront-react/providers/vendure'

const preset = new VendureProviderPreset({
apiUrl: 'https://your-vendure-api.com/shop-api',
defaultChannelToken: 'YOUR_CHANNEL_TOKEN',
locale: 'en',
currency: 'USD',
persistOptions: {
enabled: false,
},
}).toPreset()

function App() {
return (
<DataProvider platform='web' preset={preset}>
<YourApplication />
</DataProvider>
)
}

3. Use Core Hooks​

Once the DataProvider is set up, you can use hooks throughout your application:

import { useSdk, useQuery } from "@haus-storefront-react/core";

function ProductList() {
const sdk = useSdk();
const { data, isLoading, error } = useQuery({
queryKey: ["products"],
queryFn: () => sdk.search({ take: 10 }),
});

if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
if (!data) return <div>No products found</div>;

return (
<div>
{data.items.map((product) => (
<div key={product.id}>
<h3>{product.name}</h3>
<p>{product.description}</p>
</div>
))}
</div>
);
}

Basic Examples​

Examples assume a vendurePreset from VendureProviderPreset (see Quick Start).

Example 1: Shopping Cart​

import { DataProvider } from "@haus-storefront-react/core";
import { VendureProviderPreset } from "@haus-storefront-react/providers/vendure";
import { Cart } from "@haus-storefront-react/cart";
import { AddItemToOrder } from "@haus-storefront-react/add-item-to-order";

const vendurePreset = new VendureProviderPreset({
apiUrl: 'https://your-api.com/shop-api',
defaultChannelToken: 'YOUR_TOKEN',
}).toPreset();

function ShoppingApp() {
return (

<DataProvider platform='web' preset={vendurePreset}>
<ProductPage />
<CartDisplay />
</DataProvider>
); }

function ProductPage() {
return (

<div>
<h1>Product Name</h1>
<AddItemToOrder.Root productVariantId='123'>
<AddItemToOrder.QuantityInput />
<AddItemToOrder.AddButton>Add to Cart</AddItemToOrder.AddButton>
</AddItemToOrder.Root>
</div>
); }

function CartDisplay() {
return (

<Cart.Root>
{({ data: order, isLoading }) => (
<>
{isLoading && <div>Loading cart...</div>}
{order && (
<>
<Cart.Items />
<Cart.Totals />
<Cart.CheckoutButton>Checkout</Cart.CheckoutButton>
</>
)}
<Cart.Empty>
<p>Your cart is empty</p>
</Cart.Empty>
</>
)}
</Cart.Root>
); }

import { DataProvider } from "@haus-storefront-react/core";
import { VendureProviderPreset } from "@haus-storefront-react/providers/vendure";
import { ProductList } from "@haus-storefront-react/product-list";
import { Search } from "@haus-storefront-react/search";

const vendurePreset = new VendureProviderPreset({
apiUrl: "https://your-api.com/shop-api",
defaultChannelToken: "YOUR_TOKEN",
}).toPreset();

function Storefront() {
return (

<DataProvider platform='web' preset={vendurePreset}>
<Search.Root>
<Search.Input placeholder='Search products...' />
<Search.Results>
<Search.Products />
</Search.Results>
</Search.Root>

<ProductList.Root>
<ProductList.Items>
{({ items }) => (
<div>
{items.map((item) => (
<ProductList.Item key={item.id} product={item}>
<ProductList.Image />
<ProductList.Name />
<ProductList.Price />
<ProductList.AddToCartButton />
</ProductList.Item>
))}
</div>
)}
</ProductList.Items>
<ProductList.Pagination />
</ProductList.Root>
</DataProvider>

);
}

Example 3: Using Hooks Directly​

import {
DataProvider,
useSdk,
useQuery,
useMutation,
} from "@haus-storefront-react/core";
import { useActiveOrder } from "@haus-storefront-react/hooks";

function CustomCart() {
const sdk = useSdk();
const { data: order, isLoading } = useActiveOrder();

const addItemMutation = useMutation({
mutationFn: (input) => sdk.addItemToOrder(input),
onSuccess: () => {
console.log("Item added to cart!");
},
});

const handleAddToCart = () => {
addItemMutation.mutate({
productVariantId: "123",
quantity: 1,
});
};

if (isLoading) return <div>Loading...</div>;

return (

<div>
<h2>Cart ({order?.lines.length || 0} items)</h2>
{order?.lines.map((line) => (
<div key={line.id}>
{line.productVariant.name} - {line.quantity} x {line.linePriceWithTax}
</div>
))}
<button onClick={handleAddToCart}>Add Item</button>
</div>
); }

Configuration Options​

DataProvider Options​

DataProvider accepts a preset (recommended for Vendure) or sdkInstance plus options:

import { DataProvider } from '@haus-storefront-react/core'
import { VendureProviderPreset } from '@haus-storefront-react/providers/vendure'

const preset = new VendureProviderPreset({
apiUrl: 'https://your-api.com/shop-api',
defaultChannelToken: 'YOUR_CHANNEL_TOKEN',
locale: 'en',
currency: 'USD',
persistOptions: {
enabled: true,
maxAge: 3600000, // 1 hour in milliseconds
},
}).toPreset()

<DataProvider
platform='web' // or "native" - auto-detected if not specified
preset={preset}
options={{
enabledFeatures: {
customPriceCurrency: (currencyCode) =>
currencyCode === 'SEK' ? 'kr' : currencyCode,
},
pluginConfigs: [
// Your plugin configs here
],
}}
>
<App />
</DataProvider>

Note: The legacy provider and vendureToken props were removed. Use VendureProviderPreset and defaultChannelToken instead. Vendure interceptors are applied automatically by the preset.

Key Concepts​

Headless Components​

All components are "headless" - they provide logic and state management but allow complete UI customization. You control the styling and layout.

Compound Components​

Many components use the compound component pattern for flexibility:

<Cart.Root>
<Cart.Items>
<Cart.Item orderLine={line}>
<Cart.Item.Image />
<Cart.Item.Price />
</Cart.Item>
</Cart.Items>
<Cart.Summary>{/* Summary content */}</Cart.Summary>
</Cart.Root>

asChild – Use Your Own Elements in Compound Components​

Many components in the Haus Storefront libraries have an asChild prop. This allows you to replace the underlying HTML element (such as a <button>, <input>, or <form>) with your own component or element, without losing access to all the logic, props, and context.

This is particularly useful if you want to use your own styling, a UI library, or for example, a Next.js Link instead of a regular <a> tag.

Example: Replace Button with Your Own Component​

import { Login } from "@haus-storefront-react/authentication";

<Login.Root>
<Login.Form asChild>
<form className='my-form'>
<Login.EmailInput asChild>
<input className='my-input' />
</Login.EmailInput>
<Login.PasswordInput asChild>
<input className='my-input' />
</Login.PasswordInput>
<Login.SubmitButton asChild>
<button className='my-button'>Log in</button>
</Login.SubmitButton>
</form>
</Login.Form>
</Login.Root>;

In the example above:

  • All props and event handling from the Login components are passed through to your own elements.
  • You can use any element (e.g., <button> or a custom React component) and still get the correct logic and accessibility.

Why Use asChild?​

  • Full control over markup and styling – You decide exactly which element is rendered.
  • Keep all logic – You still get the correct props, events, and accessibility attributes.
  • Integrate with UI libraries – Works with Chakra UI, Material UI, Tailwind, or any other UI library.

asChild is built on a "slot" pattern and works in all compound components where it's available.

Render Props​

Components often use render props to provide context:

<ProductList.Root>
{({ products, isLoading, error }) => {
// Access context data
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error loading products</div>;

return <div>{/* Your UI */}</div>;

}}

</ProductList.Root>

Platform Detection​

Components work on both web (React) and mobile (React Native) platforms. The library automatically detects the platform and uses appropriate primitives. You can explicitly set the platform if needed:

  • Web: Runs in browsers, uses localStorage for persistence
  • Native: Runs in React Native, uses AsyncStorage for persistence
import { DataProvider } from '@haus-storefront-react/core'
import { VendureProviderPreset } from '@haus-storefront-react/providers/vendure'

const preset = new VendureProviderPreset({
apiUrl: 'https://your-api.com/shop-api',
defaultChannelToken: 'YOUR_CHANNEL_TOKEN',
}).toPreset()

<DataProvider platform='web' preset={preset}>
<App />
</DataProvider>

TypeScript types on React Native​

By default, all component props and hook signatures are typed for the web (DOM props like onClick, className, CSSProperties styles). In a React Native app, opt in to the native type variants by importing the native type augmentation once, at your app's entry point:

// App entry (e.g. App.tsx or app/_layout.tsx)
import '@haus-storefront-react/shared-types/native'

This switches every platform-dependent type in @haus-storefront-react/* to its native variant for the whole TypeScript program:

  • Component slot props become React Native props (ViewProps, TextProps, TextInputProps, onPress, StyleProp styles, etc.)
  • Hooks with platform-specific signatures (like useElementSize, useInputChangeEvent and useWindowSize from @haus-storefront-react/common-hooks) show their native signatures

The import is type-only in effect (the module has no runtime side effects), and web apps are unaffected — without the import, all types stay web-flavored.

Next Steps​

Now that you have the basics set up, explore the documentation:

  1. Learn about the Core Library: Understand the DataProvider, SDKs, and hooks
  2. Explore Storefront Components: Build your storefront with our pre-built components
  3. Use Storefront Hooks: Access e-commerce functionality with React hooks
  4. Customize Components: Use the ComponentProvider to customize component rendering
  5. Integrate with Vendure: Learn about plugin configurations and type-safe integrations
  6. Level up with Advanced Guides: Dive into Advanced Playbook for component composition, SDK extensions, and plugin strategies

Happy building!

Made with ❤️ by Haus Tech Team