Override UI elements of product modules in the InStore colleague app to match brand, workflow, and localization requirements.
Ask about this Page
Copy for LLM
View as Markdown
Product modules in
modular_store share a default UI theme that is configured in the InStore Center on the Theme tab of the environment.
You can override the theme and other presentation aspects for the following product modules that run inside the InStore colleague app:InStore_PaymentInStore_RefundInStore_DeviceManagementInStore_CashManagement
You must call the relevant API before these modules are called. You can override the following:
Override theme
Product modules adopt the colors defined on the Theme tab in the InStore Center unless you explicitly override them. To override the theme, follow these steps:
- Import the
useStorehook fromInStore_State. - Access
configurationfromuseStorein your top-level layout (for example,InStore_Shell/src/views/layout.tsx). - Call
configuration.setOverrideCoreTheme(true)before any product module mounts. - Provide custom
themeOptionsthrough the theme provider (for example,InStore_Shell/src/providers/theme.tsx).
import { useStore } from "InStore_State/store";
const Layout = () => {
const { configuration } = useStore();
// ...
};
useEffect(() => {
configuration.setOverrideCoreTheme(true);
}, []);
import React, { PropsWithChildren } from 'react';
import { ThemeProvider as TP } from 'InStore_State/theme';
import customTheme from '../theme/customTheme';
const ThemeProvider = ({ children }: PropsWithChildren) => (
<TP rootElementId="app" themeOptions={customTheme}>
{children}
</TP>
);
Front-end modules use Tailwind. Product modules use the 12‑column Grid (v1) version of Material UI (MUI) 5, specifically:
- MUI base v. 5.0.0-beta.34
- MUI icons-material v. 5.8.0
- MUI material v. 5.8.1
- MUI system v. 5.15.0
The following examples show how to configure the elements' size and color, but not the text.
The action button bar background color is not part of Material UI. Set it with the Base Background control on the Environment > Theme tab in the InStore Center.
Payment types structure
<Grid className="instore-payment-entry-container">
<Grid item xs={12} md={6} className="instore-payment-amount-section">
<Grid item xs={12}>
<Typography className="instore-payment-amount-header" />
</Grid>
<Grid item xs={12}>
<KeypadEntry className="instore-payment-amount-keypad" />
</Grid>
</Grid>
<Grid item xs={12} md={6} className="instore-payment-types-section">
<Grid item xs={12}>
<Typography className="instore-payment-types-header" />
</Grid>
<Grid item xs={12}>
<Grid>
<TenderButton className="instore-payment-types-button-${type}" />
{/* {type} is cash, credit, paybylink, etc. */}
</Grid>
</Grid>
</Grid>
</Grid>
Cash structure
<Grid className="instore-payment-entry-container">
<Grid item xs={12} md={6} className="instore-payment-amount-section">
<Grid item xs={12}>
<Typography className="instore-payment-amount-header" />
</Grid>
<Grid item xs={12}>
<KeypadEntry className="instore-payment-amount-keypad" />
</Grid>
</Grid>
<Grid item xs={12} md={6} className="instore-cash-section">
<Grid item xs={12}>
<Typography className="instore-cash-header" />
</Grid>
<Grid item xs={12}>
<Grid>
<Button className="instore-cash-button-${value}" /> {/* List of buttons */}
</Grid>
</Grid>
</Grid>
</Grid>
Cash drawer structure
<Grid>
<Grid item xs={12} md={6}>
<Grid item xs={12}>
<Typography className="instore-cash-promp-drawer" />
</Grid>
</Grid>
</Grid>
Change due structure
<Grid className="instore-change-due-container">
<Grid item xs={12}>
<Typography className="instore-cash-change-row-0" />
<Typography className="instore-cash-change-row-1" />
<Typography className="instore-cash-change-row-2" />
<Typography className="instore-cash-change-row-3" />
</Grid>
</Grid>
Credit processing structure
<Grid className="instore-payment-entry-container">
<Grid item xs={12}>
<Typography className="instore-credit-process-label" />
<Typography className="instore-credit-process-amount" />
</Grid>
</Grid>
Gift card entry structure
<Grid>
<Grid item xs={12} md={6}>
<Grid className="instore-gift-cart-header">
<Grid item xs={12}>
<Button className="instore-gift-cart-camera-button" />
<Typography className="instore-gift-cart-label" />
</Grid>
<Grid item xs={12}>
<KeypadEntry className="instore-gift-cart-keypad" />
</Grid>
</Grid>
</Grid>
</Grid>
HTML structures for Pay On Account
Use this wrapper to introduce the POA component:
<Paper elevation={0} className='instore-POA-paper-background'>
<Container className='instore-POA-confirmation-container'>
HTML structure for POA Company Name label and field
<>
<Grid item xs={12} sm={6}>
<Typography
className='instore-POA-company-name-label'
>
{t('POA.companyName')}
</Typography>
</Grid>
<Grid
item
xs={12}
sm={6}
className='instore-POA-company-name-field'
>
<Typography
variant='subtitle1'
id='customer-company-name'
>
{customer.company}
</Typography>
</Grid>
</>
HTML structure for POA Customer Number label and field
<>
<Grid item xs={12} sm={6}>
<Typography
variant='h6'
className='instore-customer-number-label'
>
{t('POA.customerNumber')}
</Typography>
</Grid>
<Grid item xs={12} sm={6}>
<Typography
variant='subtitle1'
className='instore-customer-number-field'
>
{customer.customer_number}
</Typography>
</Grid>
</>
HTML structure for POA Customer Email label and field
<>
<Grid item xs={12} sm={6}>
<Typography variant='h6' className='instore-customer-email-label'
>
{t('POA.customerEmail')}
</Typography>
</Grid>
<Grid item xs={12} sm={6}>
<Typography variant='subtitle1' className='instore-customer-email-field'
>
{customer.email}
</Typography>
</Grid>
</>
HTML structure for POA Account IDs label and drop-down
<>
<Grid item xs={12} sm={6}>
<Typography variant='h6' className='instore-POA-account-id-label'
>
{t('POA.accountID')}
</Typography>
</Grid>
<Grid item xs={12} sm={6}>
<Typography variant='subtitle1' className='instore-customer-account-number'
>
{accountNumber}
</Typography>
</Grid>
<Grid item xs={12} sm={6}>
<FormControl className='instore-POA-account-dropdown'
>
<Select
>
<MenuItem
>
{account}
</MenuItem>
</Select>
</FormControl>
</Grid>
</>
HTML structure for POA page divider
<Grid item xs={12} sm={6}>
<Divider variant='middle' className='instore-POA-divider' />
</Grid>
HTML structure for POA Payment Amount label and field
<>
<Grid item xs={12} sm={6}>
<Typography variant='h6' className='instore-POA-payment-amount-label'
>
{t('POA.paymentAmount')}
</Typography>
</Grid>
<Grid item xs={12} sm={6}>
<Typography variant='subtitle1' className='instore-poa-payment-amount'>
{currentTenderAmount.toFormat(currencyInstance.currencyFormat)}
</Typography>
</Grid>
</>
HTML structure for POA Purchase Order label and field
<>
<Grid item xs={12} sm={6}>
<Typography variant='h6' className='instore-purchase-order-label'
>
{t('POA.purchaseOrderLabel')}
</Typography>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
value={purchaseOrder}
className='instore-POA-purchase-order-input'
/>
</Grid>
</>
Pay On Account HTML rendered on the UI
Override strings
For core product modules, InStore retrieves UI strings from the InStore API. For accelerator modules, API is consulted first and the predefined language bundles second. Override only the keys you want to change. Other keys fall back to defaults.
Follow these steps to override strings:
- Specify overrides as shown in this example. If you have multiple languages, add a section for each language as shown.
- Define a payload
{ ... }for each section based on the main payload in the example. The payload only needs to include the strings to be overridden, you don't need to include strings in the payload if you don’t want to override them. - Get an administrator access token. The credentials used here are the same as the ones you use with all InStore APIs.
- Send a PUT request to
/:tenantId/translations, and then send the payload. You must include{{login_token}}in the header of your request. For example, in the PUT call, insert the{{login_token}}as the value for the token key that pairs with the header. - The returned response is the updated bundle in JSON format.
Route
| Path | Type | Description |
|---|---|---|
| /:tenantId/translations | PUT | Override default translations for supported locales. |
Request
| Field | Type | Description |
|---|---|---|
translations | object | Container for per-locale override objects. |
Example
The following example replaces the string
Cash Drawer with Till in the en-GB bundle.{
"translations": {
"en-CA": { },
"fr-CA": { },
"en-GB": {
...
"CashCollection": {
"promptMessage": "Select or enter cash Remaining Balance.",
"promptMessageChangeDue": "Please give Change Due to customer and close the till.",
"userMessageCreditApproved": "Card payment approved."
},
"CashDrawer": {
"promptMessageClose": "Confirm the till is closed and press OK.",
"promptMessageSelection": "Select the Till and Reason for the count.",
"promptMessagePayInOpen": "Place cash received in drawer, close the drawer, and press DONE.",
"promptMessagePayOutOpen": "Remove disbursement amount from drawer, close the drawer, and press DONE.",
"promptMessageCashAuditOpen": "Remove transfer amount from drawer, close the drawer, and press DONE.",
"userMessageOpenCashDrawer": "Till open.",
"userMessageCashDrawerClosed": "Till closed."
},
"CashManagement": {
"promptMessageMenu": "Please Select a cash management process.",
"promptMessagePayIn": "Enter the Amount Received and select a Reason.",
"promptMessagePayOut": "Enter the disbursement amount and select a reason.",
"promptMessageCashCount": "Enter the Count for each currency denomination.",
"promptMessageCashCountSummary": "Enter the total counted cash.",
"promptMessageCountAcceptance": "Choose to ACCEPT Count or RECOUNT.",
"promptMessageCashAudit": "Select a Till, review the data and press DONE to finish.",
"promptMessageSafeDeposit": "Select the Till and Reason and press NEXT to continue.",
"promptMessageSafeReserve": "Leave the Reserve Amount in the drawer. Close the drawer. Place the Deposit Amount in the safe, and press DONE.",
"promptMessageBankDepositReserve": "Leave the Reserve Amount in the safe. Send the deposit amount to the bank, and press DONE."
},
...
}
}
}
You can override strings for only accelerator modules by accessing your local copy of the InStore Client
translation.json file for the language that is in use. You can obtain a language bundle with relevant keys from commercetools.Note that any overrides present in the API take precedence over bundle overrides.
Override tender labels
- Log in to the InStore API server with administrator credentials and obtain a token.
- Add the token to the request header.
- Send
PUT /:tenantId/translationswith a payload containing updated button labels under the relevant module key (for example,Checkout). - A successful update returns status code
202and the updated labels.
Route
| Path | Type | Description |
|---|---|---|
| /:tenantId/translations | PUT | Override default translations for supported locales. |
Request
| Field | Type | Description |
|---|---|---|
translations | object | Container for per-locale translation overrides. |
Example
{
"translations": {
"en-US": {
"Checkout": {
"buttons": {
"cash": "CASH",
"typeCards": "CREDIT / DEBIT",
"giftCard": "GIFT CARD",
"digitalWallet": "DIGITAL WALLET",
"poa": "PAY-ON-ACCOUNT",
"payByLink": "PAY BY LINK"
}
}
}
}
}
Override tender order and icons
- Log in to the InStore API server with administrator credentials and obtain a token.
- Add the token to the request header.
- Send
PUT /:tenantId/payment-buttonswith a payload describing order and icons. - A successful update returns status code
202and the updated configuration.
Route
| Path | Type | Description |
|---|---|---|
| /:tenantId/payment-buttons | PUT | Update tender display configuration and return the tenant document. |
Request fields
| Field | Type | Description | Example |
|---|---|---|---|
paymentButtons | array | Array of button configuration objects. | See example |
paymentButtons[].key | string | Identifier of the payment button to update. | creditCard |
paymentButtons[].icon | string | Material UI icon component name. | CreditCard |
paymentButtons[].order | integer | Display order (1–10). | 1 |
Example
{
"paymentButtons": [
{ "key": "creditCard", "icon": "CreditCard", "order": 1 },
{ "key": "cash", "icon": "Money1", "order": 2 }
]
}
To optimize performance, InStore loads only a subset of MaterialUI icons. If you want to use an icon that is not included in the preloaded set, contact the InStore support team.
Override print options
You can override print options from any module in
modular_store. For example, you can omit a receipt option on the cart if certain conditions on the customer record are not met.-
Import
useStorefromInStore_State/store. -
Access
configurationfromuseStore. -
Call
configuration.setOverridePrintOptions([...])to set allowed print options for Checkout or Refund in theInStore_Coremodule.import { useStore } from 'InStore_State/store'; -
Call
setOverridePrintOptionsin any part of the component to override print options on Checkout or Refund in the InStore core application.configuration.setOverridePrintOptions(['Paper']); //Options: Paper, Email, Text, and None
Make sure that the value of
setOverridePrintOptions is either an array of strings or null. If this override consists of null, then InStore uses the values that were set by the Receipt_Print_Options administration parameter in the InStore Center.An array will replace the values that were configured by the administration parameter.
For more information, see how to set an event type for capturing the choice of receipt.
Add payment details to the Totals box
You can add your own specific information to display to your colleagues at the top of the Totals box during checkout. For example, you can display loyalty benefits, customer entitlements, or applied discount information to help the colleague to explain the amount due for a customer.
The additional information is added within a flexibly sized component called the
MoneyBoxInjection. You can call the InStore moneyBoxInjection property at render time.To display payment details within the Totals box, do the following:
-
Follow the steps for overriding the theme and add the following to the
configuration:Injector.inject({ tenantId: "a1a1-b2b2-c3c3-d4d4", moneyBoxInjection: { items: [ { label: "Shopper due 1000 Loyalty points on checkout", alignment: "center" }, { type: "divider" }, { label: "Customer Credit Available to Use: £180.50", alignment: "right" }, { type: "divider" }, { label: "Price Match Applied:", value: "-£10.00", alignment: "left" }, ] } }); -
For each item in the
itemsarray, assign one of the following options:{ "label": "Promo: Buy 1 Get 1 Free!", "value": "-£1.00", "alignment": "center" } -
Implement a divider (a horizontal line) by inserting the following text:
{ "type": "divider" }Use theming described elsewhere in this topic to style line thickness, color, and spacing.
-
Use theming overrides to style the
MoneyBoxInjectioncomponent. For example:MoneyBoxInjection: { styleOverrides: { root: { "&.instore-moneybox-injection": { textAlign: themeOptions.defaultTextAlign || "left", margin: themeOptions.moneyBoxMargin || "4px 0", fontSize: themeOptions.moneyBoxFontSize || "14px", color: themeOptions.moneyBoxTextColor || "#000", "& .instore-moneybox-item-left": { textAlign: "left" }, "& .instore-moneybox-item-center": { textAlign: "center" }, "& .instore-moneybox-item-right": { textAlign: "right" }, "& .instore-moneybox-separator": { borderTop: `1px solid ${themeOptions.moneyBoxSeparatorColor || "rgba(0,0,0,0.3)"}`, margin: themeOptions.moneyBoxSeparatorSpacing || "4px 0", }, } } } }