Let buyers apply or remove a coupon code with a secure, fully styleable input.
The Coupon component (fs-coupon) renders a coupon code field and Apply button inside a secure iframe served from FastSpring's domain. Applying or removing a code updates the session through the SDK, and components that show session-derived values, such as totals, refresh automatically.
This page is the complete reference for the Coupon component: how to mount it, the options it accepts, the states it exposes for styling, and every style category and property available. For setup context, see the Integration Guide.
Mount
Add a target element to your HTML:
<div id="coupon-element"></div>Then create the component from your sdk instance and mount it:
const couponComponent = sdk.components.create('fs-coupon', {
// options + style go here
});
couponComponent.mount('#coupon-element');Component options
Top-level options passed alongside style:
| Option | Type | Default | Description |
|---|---|---|---|
presentation | 'collapsed' | 'expanded' | 'collapsed' | Field visibility. 'collapsed': the field is hidden behind a "Have a coupon code?" link. 'expanded': the field is always visible. |
labelMode | 'floating' | 'fixed' | 'floating' | Label placement. 'floating': the label sits inside the input and moves up on focus or when filled. 'fixed': a static label sits above the field, and the field shows a real placeholder. |
What the buyer sees
A "Have a coupon code?" link ('collapsed'), or a "Coupon Code" field and Apply button ('expanded'). Clicking the link reveals the field and focuses it. Apply stays disabled until a code is entered.
A centered "{code} applied!" chip in teal, with the code in italics and a × to remove it. It also shows on load when the session already has a coupon, including after a page reload.
The session updates and onSessionUpdated fires with the new coupon and couponApplied values. Totals in other components, such as the Pay button, refresh without a reload.
To start the checkout with a coupon already applied, pass cart.couponCode when you create the session with the Sessions API. The component then opens on the applied chip.
How styling works
Styling is configured through a style object passed at component creation. Each state contains one or more style categories (input, button, chip, etc.) that group related properties.
sdk.components.create('fs-coupon', {
style: {
state: {
default: { /* base styles */ },
hover: { /* applied on hover */ },
focus: { /* applied on focus */ },
disabled: { /* applied to disabled controls */ },
error: { /* applied in error state */ },
},
},
});Style precedence: FastSpring uses the first value it finds, in this order:
- The style you set for the current state (e.g.,
state.focus.input) - The style you set for the
defaultstate (e.g.,state.default.input) globalStylespassed toFastSpring.init()- FastSpring's built-in default (the Default column in the tables below)
Coming from the Card component? The
inputcategory uses the same property names as the Card's input where the two overlap, so shared keys carry over. Not every Card key is supported (for example,transition).
Available states
| State | When applied |
|---|---|
default | Always (the base styling) |
hover | The pointer is over the link, the Apply button or the remove icon |
focus | The input has keyboard focus |
disabled | During the apply or remove round-trip. Apply is also disabled while the field is empty |
error | The backend rejects the code after the buyer clicks Apply |
For what each state changes out of the box, see Default values per state.
Style categories
Each category below targets a specific part of the Coupon component. Select a card to jump to its full property reference.
The default font family for every category is Helvetica Neue, helvetica, arial, sans-serif, written as Helvetica Neue stack in the tables below. The component's base text is 14px in #4B5563.
input: the coupon field
input: the coupon field| Property | Type | Default | Description |
|---|---|---|---|
backgroundColor | string | #fff | Input background. background is accepted as a legacy alias. |
color | string | #4B5563 | Text color |
borderColor | string | #DEE2E6 | Border color |
borderRadius | string | 4px | Corner radius |
fontSize | string | 16px | Font size |
fontFamily | string | Helvetica Neue stack | Font family |
height | string | 48px | Input height. The Apply button matches it. |
padding | string | 22px 16px 8px 16px (floating), 12px 16px (fixed) | Inner padding |
placeholderColor | string | transparent | Placeholder color. Transparent in floating mode, where the label acts as the placeholder; set a visible color when using labelMode: 'fixed'. |
state.error.input styles the field while the backend has rejected the code. It accepts borderColor and color (both default #EB1431), plus backgroundColor and fontFamily (defaults: the resting values above). These are the same four properties state.error.input takes on Card and Email.
The field label is #64748B. In floating mode it moves to the top at .8rem when the field is focused or filled; in fixed mode it sits above the field at 14px, and the empty field shows the placeholder "Enter Coupon Code".
button: the Apply button
button: the Apply button| Property | Type | Default | Description |
|---|---|---|---|
background | string | #008AFF | Button background |
color | string | #fff | Button label color |
fontWeight | string | number | 400 | Button label weight |
borderRadius | string | 4px | Corner radius |
The button is 83px wide, with a 16px Helvetica Neue stack label.
chip: the applied-code chip
chip: the applied-code chip| Property | Type | Default | Description |
|---|---|---|---|
background | string | transparent | Chip background |
color | string | #27B2A8 | Applied-code text color |
borderRadius | string | 0 | Corner radius |
padding | string | 4px | Chip padding |
gap | string | 8px | Gap between the text and remove icon |
fontFamily | string | Helvetica Neue stack | Font family |
fontSize | string | 12px | Font size |
fontWeight | string | number | 400 | Font weight |
iconSize | string | 16px | Remove-icon size |
iconColor | string | #7D8A9B | Remove-icon color |
The applied code itself is shown in italics.
inlineError: inline validation error messages
inlineError: inline validation error messagesShown 4px below the field when the backend rejects a code. Same category name and properties as on Card and Email, so one error style block works across all three.
| Property | Type | Default | Description |
|---|---|---|---|
color | string | #EB1431 | Error text color |
fontSize | string | 12px | Error font size |
fontWeight | string | number | 400 | Error font weight |
fontFamily | string | Helvetica Neue stack | Error font family (follows the component font) |
backgroundColor | string | transparent | Error message background |
Deprecated:
erroris the old name for this category. It still applies, logs one console warning per component, and loses toinlineErrorwhen both are set.inlineError.colorno longer sets the field's error border; usestate.error.input.borderColor.
toggle: the coupon link
toggle: the coupon linkStyles the "Have a coupon code?" link shown in 'collapsed' presentation. The link is underlined and centered.
| Property | Type | Default | Description |
|---|---|---|---|
color | string | #008AFF | Link text color |
Default values per state
Out of the box, the Coupon component visually changes for hover, focus, disabled, and error.
hover
hoverApplied when the pointer is over an element.
| Property | Default override value |
|---|---|
toggle.color | #2563EB |
button.background | #2563EB |
chip.iconColor | #4B5563 |
focus
focusApplied when the input has keyboard focus.
| Property | Default override value |
|---|---|
input.borderColor | #2563EB |
| Focus glow | 0 0 0 4px rgba(0, 138, 255, .2) (soft blue glow) |
| Floating label color | #2563EB |
disabled
disabledApplied during the apply or remove round-trip. The Apply button also looks disabled while the field is empty.
| Property | Default override value |
|---|---|
input.backgroundColor | #E7E7E7 |
input.color | #64748B |
button.background | #84C6FF |
error
errorApplied when the backend rejects the code. The inlineError message appears 4px below the field.
| Property | Default override value |
|---|---|
input.borderColor | #EB1431 |
input.color | #EB1431 |
| Focus glow | 0 0 0 4px color-mix(in srgb, #EB1431 15%, transparent) |
| Floating label color | #EB1431 |
Under error, input accepts borderColor, color, backgroundColor and fontFamily, and inlineError accepts all its properties. inlineError styling is also accepted under default; the error value wins when both are set.
Full example
sdk.components.create('fs-coupon', {
presentation: 'expanded',
style: {
state: {
default: {
input: { background: '#0b1220', color: '#f1f5f9', borderColor: '#283449', borderRadius: '10px', placeholderColor: '#64748b' },
button: { background: '#6366f1', color: '#ffffff', fontWeight: '600', borderRadius: '10px' },
chip: { color: '#a5b4fc', iconColor: '#64748b' },
inlineError: { color: '#fca5a5', backgroundColor: '#1f1a2e' },
toggle: { color: '#818cf8' },
},
focus: { input: { borderColor: '#6366f1' } },
error: { input: { borderColor: '#f87171', color: '#fecaca' } },
hover: { button: { background: '#4f46e5' }, toggle: { color: '#a5b4fc' } },
disabled: { button: { background: '#3730a3' } },
},
},
}).mount('#coupon-element');