Quick orders
Front-Commerce's QuickOrder component allows customers to add products to their cart by entering an SKU and a quantity. This component is self-contained and renders a compact form designed to be integrated into different contexts. This guide explains how to integrate this feature into your application.
The <QuickOrder /> component adds a user interface allowing your customers to
directly order items based on their SKU
Integrate QuickOrder into your project
You must include the component in your page with the following lines:
import React from "react";
import QuickOrder from "theme/modules/QuickOrder";
const MyComponent = () => {
return (
<div>
<QuickOrder />
</div>
);
};
If you need to customize the component, you can, of course, override it.
Enable the Quick Order page
The /quick-order route is gated by the quickOrder extension feature flag.
When the flag is inactive, the route returns 404 and no link is rendered in
the theme-chocolatine header. The flag is enabled automatically by
@front-commerce/adobe-b2b and @front-commerce/gezy-marketplace.
To enable it from any other extension or project, register the feature in your
extension's unstable_lifecycleHooks.onFeaturesInit:
return defineRemixExtension({
// ...
unstable_lifecycleHooks: {
onFeaturesInit: (hooks) => {
hooks.registerFeature("quickOrder", { flags: { enabled: true } });
},
},
});
Once enabled, a lightning icon appears in the theme-chocolatine header
(between search and wishlist, desktop only) and points to /quick-order. The
flag is resolved at build time — toggling it through an environment variable at
runtime is not supported.
Configure the Quick Order page
The page configuration is split across two override points so that you only touch the layer you actually need to customize:
theme/modules/CsvEntries/useCsvEntriesConfig— the CSV codec (columns, delimiter, quoting). See the dedicated CSV format guide. Overriding the codec applies automatically to every feature that composes it — the Quick Order upload, the template download, and the order detail CSV download — keeping them in sync by construction. The codec mechanics (parseCsv,generateCsvand the associated types) live in@front-commerce/theme-chocolatine/csvand are deliberately outside the theme override surface.theme/pages/QuickOrder/useQuickOrderConfig— the Quick Order page bindings (sample rows for the downloadable template, rowPicker, submit mutation, configuration modal). Override this hook when you need to swap how the page renders or submits rows.QuickOrderConfigextendsCsvEntriesConfig, so you still get every codec field on it.
Customize the Quick Order page (page bindings)
Override useQuickOrderConfig to change the row picker, the submit mutation or
the configuration modal.
import type { QuickOrderConfig } from "theme/pages/QuickOrder/defaultConfig";
import myQuickOrderConfig from "./myQuickOrderConfig";
const useQuickOrderConfig = (): QuickOrderConfig => myQuickOrderConfig;
export default useQuickOrderConfig;
The QuickOrderConfig type (from theme/pages/QuickOrder/defaultConfig)
extends CsvEntriesConfig with these page-specific fields:
| Field | Required | Purpose |
|---|---|---|
csvSampleLines | yes | Rows used to build the downloadable CSV template on the Quick Order page. |
Picker | yes | Component used to render each row. Receives the full entry as a prop so it can read any custom field your CSV columns added. |
useSubmitItems | yes | Hook that returns the function called when the user clicks "Add to cart". Receives the valid entries and must return a QuickOrderSubmitResult (success flag, optional error message and per-product errors). |
needsConfiguration | yes | (entry) => boolean — drives the visibility of a "Configure" button on each row. The default flags configurable products imported via CSV (rows whose resolved product still carries configurations). |
useConfigurationModal | yes | Hook called once at the page level. Returns { showFor(entry, onComplete), modalElement } — modalElement is rendered by the page, showFor is invoked by the page (on "Configure" click) and by custom pickers (via the optional openConfigurationModal prop, see below). |
The default config (defaultQuickOrderConfig) wires the standard SKU-based flow
against the addMultipleItemsToCart core mutation. Extensions can import it and
spread its fields to override only what changes.
Example: replace the submit mutation
import { defaultQuickOrderConfig } from "theme/pages/QuickOrder/defaultConfig";
import useMyCustomSubmit from "./useMyCustomSubmit";
const myQuickOrderConfig = {
...defaultQuickOrderConfig,
useSubmitItems: useMyCustomSubmit,
};
export default myQuickOrderConfig;
The useSubmitItems hook is called once at the page level, so it can wire
loaders, mutations or even a useRevalidator to refresh the rest of the page
when items are added.
Example: plug a custom configuration modal
useConfigurationModal lets you replace the default per-row modal (which reuses
SelectProductConfigurationModal) with your own. The hook is called once at the
page level and must return:
modalElement: the JSX rendered once near the top of the page (typically a<Modal>whoseisOpenis driven by internal state).showFor(entry, onComplete): opens the modal for a given entry.onCompletemust be called only when the user validates — closing the modal without validating must not invoke it (so a manual pick that gets cancelled does not create a row).
import { useCallback, useRef, useState } from "react";
import type {
QuickOrderConfigurationModal,
QuickOrderEntry,
} from "theme/pages/QuickOrder/defaultConfig";
const useMyConfigurationModal = (): QuickOrderConfigurationModal => {
const [isOpen, setIsOpen] = useState(false);
const [entry, setEntry] = useState<QuickOrderEntry | null>(null);
const onCompleteRef = useRef<((entry: QuickOrderEntry) => void) | null>(null);
const close = useCallback(() => {
setIsOpen(false);
setEntry(null);
onCompleteRef.current = null;
}, []);
const showFor = useCallback<QuickOrderConfigurationModal["showFor"]>(
(nextEntry, onComplete) => {
onCompleteRef.current = onComplete;
setEntry(nextEntry);
setIsOpen(true);
},
[],
);
const handleValidate = () => {
if (!entry || !onCompleteRef.current) return;
onCompleteRef.current({ ...entry /* + your custom bake */ });
close();
};
return {
showFor,
modalElement: (
<MyCustomModal
isOpen={isOpen}
product={entry?.product}
onValidate={handleValidate}
onRequestClose={close}
/>
),
};
};
export default useMyConfigurationModal;
Auto-pop the modal at pick time
A custom Picker (passed via config.Picker) can opt in to a new
openConfigurationModal prop. The page forwards the modal's showFor through
this prop so the picker can intercept its inner pick callback and only emit
onStatusUpdate("valid", …) once the modal has been validated — mirroring how
<ProductPicker> handles configurable products internally.
import QuickOrder from "theme/modules/QuickOrder";
import type { QuickOrderPickerProps } from "theme/pages/QuickOrder/defaultConfig";
const MyPicker = ({
entry,
onStatusUpdate,
openConfigurationModal,
...rest
}: QuickOrderPickerProps) => {
const handleStatusUpdate = (status, product, statusText) => {
if (status === "valid" && product && openConfigurationModal) {
// Intercept: open the modal, only emit "valid" once the user validates.
openConfigurationModal({ ...(entry ?? {}), product }, (updatedEntry) => {
onStatusUpdate?.("valid", updatedEntry.product, statusText);
});
return;
}
onStatusUpdate?.(status, product, statusText);
};
return (
<QuickOrder
{...rest}
sku={entry?.sku}
onStatusUpdate={handleStatusUpdate}
/>
);
};
The default picker ignores openConfigurationModal, so a config that does not
need auto-pop simply does not provide a custom picker.