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