Override UI elements of product modules in the InStore colleague app to match brand, workflow, and localization requirements.
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_Payment
InStore_Refund
InStore_DeviceManagement
InStore_CashManagement
You must call the relevant API before these modules are called. You can override the following:
Override theme
- Import the
useStore
hook fromInStore_State
. This was previously called/store
. - Access
configuration
fromuseStore
in your top-level layout (for example,InStore_Shell/src/views/layout.tsx
). - Call
configuration.setOverrideCoreTheme(true)
before any product module mounts. - Provide custom
themeOptions
through 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>
);
- 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.
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
InStore retrieves UI strings from predefined language bundles. Override only the keys you want to change. Other keys fall back to defaults.
Follow these steps to override strings:
- In the InStore GitHub repository, in the client/public folder, locate and copy the
locales
language bundles for product modules. You can use the bundles as a reference when specifying strings to override. - 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
Cash Drawer
with Till
in the en-GB
bundle.{
"translations": {
"en-CA": { },
"fr-CA": { },
"en-GB": {
"App": {
"system_error": "Undefined system error",
"initialization_error": "Unable to initialize session!",
"invalid_request": "Invalid process requested"
},
"PaymentEntry": {
"promptMessage": "Enter Remaining Balance, then select Payment Type.",
"promptMessageAdditionalPayment": "Enter additional remaining balance, then select Payment Type.",
"promptMessageCancel": "Cancelling payment...",
"userMessageCash": "Partial cash tender added",
"buttons": {
"cash": "CASH",
"card": "CREDIT / DEBIT",
"gift": "GIFT CARD",
"wallet": "DIGITAL WALLET"
}
}
}
}
}
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/translations
with a payload containing updated button labels under the relevant module key (for example,Checkout
). - A successful update returns status code
202
and 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-buttons
with a payload describing order and icons. - A successful update returns status code
202
and 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 }
]
}
Override print options
modular_store
. For example, you can omit a receipt option on the cart if certain conditions on the customer record are not met.- Import
useStore
fromInStore_State/store
. - Access
configuration
fromuseStore
. - Call
configuration.setOverridePrintOptions([...])
to set allowed print options for Checkout or Refund in theInStore_Core
module.
import { useStore } from 'InStore_State/store';
-
Call
setOverridePrintOptions
in 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
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.
Add payment details to the Totals box
MoneyBoxInjection
. You can call the InStore moneyBoxInjection
property at render time.-
Follow the steps for overriding the theme and add the following to the
configuration
:Injector.inject({ tenantId: "SF-29299292", moneyBoxInjection: { items: [ { label: "Promo: Buy 1 Get 1 Free!", alignment: "center" }, { type: "divider" }, { label: "Offer ends 31/12", alignment: "right" }, { type: "divider" }, { label: "Order Total", value: "£180.50", alignment: "left" }, ] } });
-
For each item in the
items
array, 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
MoneyBoxInjection
component. 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", }, } } } }