Split accordion
Live Preview
POINT OF SALE
See your whole business click into place
Sell anything in person and online.
Organize permissions and shifts in one place.
Capture repeat buyers and track customer insights.
Get Started
Before placing this component on another site, confirm:
- Choose the version below: Vanilla JS mount helper or Next.js client component.
- Provide your own content object (eyebrow, heading, image, and accordion items).
- Make sure your page allows custom CSS injection or include equivalent styles in your app stylesheet.
- Use your own link destinations and body copy for each accordion item.
Available Props
Use these props/content fields to customize the split accordion component:
| Field | Type | Default | What it controls |
|---|---|---|---|
eyebrow |
string |
"POINT OF SALE" |
Small label above the heading |
heading |
string |
See your whole business click into place | Main headline text |
rightImage |
string |
"https://dummyimage.com/1400x900/e5e7eb/9ca3af.png" |
Image shown on the right side |
imageAlt |
string |
"Point of sale interface preview" |
Accessible alt text for the image |
accordionItems |
Array<{ title, body, linkLabel?, linkHref? }> |
5 default items | Accordion entries and optional learn-more links |
const DEFAULT_CONTENT = {
eyebrow: "POINT OF SALE",
heading: "See your whole business click into place",
imageAlt: "Point of sale interface preview",
rightImage: "https://dummyimage.com/1400x900/e5e7eb/9ca3af.png",
accordionItems: [
{
title: "Take payments",
body: "Sell anything in person and online with a point of sale platform that works for whatever you sell.",
linkLabel: "Learn more",
linkHref: "#",
},
{ title: "Manage your team", body: "" },
{ title: "Grow your customer base", body: "" },
{ title: "Control your cash flow", body: "" },
{ title: "Connect your favorite apps", body: "" },
],
};
export function mountSplitFeaturePosSection(target, content = {}) {
const host = typeof target === "string" ? document.querySelector(target) : target;
if (!host) throw new Error("mountSplitFeaturePosSection: target element not found.");
const config = {
...DEFAULT_CONTENT,
...content,
accordionItems: content.accordionItems || DEFAULT_CONTENT.accordionItems,
};
// render + wire accordion (same logic as your component file)
// ...
}
"use client";
import { useState } from "react";
type AccordionItem = {
title: string;
body?: string;
linkLabel?: string;
linkHref?: string;
};
type SplitFeaturePosContent = {
eyebrow?: string;
heading?: string;
imageAlt?: string;
rightImage?: string;
accordionItems?: AccordionItem[];
};
const DEFAULT_CONTENT: Required<SplitFeaturePosContent> = {
eyebrow: "POINT OF SALE",
heading: "See your whole business click into place",
imageAlt: "Point of sale interface preview",
rightImage: "https://dummyimage.com/1400x900/e5e7eb/9ca3af.png",
accordionItems: [
{
title: "Take payments",
body: "Sell anything in person and online with a point of sale platform that works for whatever you sell.",
linkLabel: "Learn more",
linkHref: "#",
},
{ title: "Manage your team", body: "" },
{ title: "Grow your customer base", body: "" },
],
};
export function SplitFeaturePosSectionClient({ content = {} }: { content?: SplitFeaturePosContent }) {
const config = {
...DEFAULT_CONTENT,
...content,
accordionItems: content.accordionItems || DEFAULT_CONTENT.accordionItems,
};
const [openIndex, setOpenIndex] = useState<number | null>(null);
return (
<section className="grid min-h-[720px] grid-cols-1 lg:grid-cols-[45%_55%]">
<div className="bg-white p-10 lg:p-16">
<p className="mb-5 text-xs tracking-[0.18em] text-neutral-500">{config.eyebrow}</p>
<h2 className="mb-10 max-w-[11ch] text-5xl leading-[0.95] text-neutral-900">{config.heading}</h2>
<div className="border-t border-neutral-200">
{config.accordionItems.map((item, index) => {
const isOpen = openIndex === index;
return (
<div key={`${item.title}-${index}`} className="border-b border-neutral-200">
<button
type="button"
className="flex w-full items-center justify-between py-5 text-left text-2xl"
onClick={() => setOpenIndex(isOpen ? null : index)}
>
<span>{item.title}</span>
<span>{isOpen ? "−" : "+"}</span>
</button>
{isOpen && (
<div className="pb-5">
{item.body ? <p className="max-w-[42ch] text-neutral-600">{item.body}</p> : null}
{item.linkLabel && item.linkHref ? (
<a className="mt-3 inline-block underline" href={item.linkHref}>
{item.linkLabel}
</a>
) : null}
</div>
)}
</div>
);
})}
</div>
</div>
<div className="bg-neutral-100">
<img src={config.rightImage} alt={config.imageAlt} className="h-full w-full object-cover" />
</div>
</section>
);
}
import { SplitFeaturePosSectionClient } from "@/components/split-feature-pos-section-client";
const splitFeatureContent = {
eyebrow: "A website that turns visitors into paying guests.",
heading: "Your whole menu in a click.",
imageAlt: "Point of sale interface preview",
rightImage: "https://dummyimage.com/1400x900/e5e7eb/9ca3af.png",
accordionItems: [
{
title: "Smart menus & digital ordering",
body: "Give guests a beautiful, branded menu they can browse and order from directly on your website.",
linkLabel: "Learn more",
linkHref: "#",
},
{
title: "Accept payments, anywhere",
body: "Let guests pay online when they order, reserve, or purchase gift cards through your website.",
linkLabel: "Learn more",
linkHref: "#",
},
],
};
export default function Home() {
return <SplitFeaturePosSectionClient content={splitFeatureContent} />;
}
Accordion Section Preview
ACCORDION ONLY
Accordion section interaction
Sell anything in person and online with a unified checkout flow.
Set roles, assign access, and keep operations organized.
Build relationships with loyalty and repeat purchase data.
import { useState } from "react";
type AccordionItem = {
title: string;
body?: string;
linkLabel?: string;
linkHref?: string;
};
export function SplitAccordionSection({ items }: { items: AccordionItem[] }) {
const [openIndex, setOpenIndex] = useState<number | null>(null);
return (
<div className="border-t border-neutral-200">
{items.map((item, index) => {
const isOpen = openIndex === index;
return (
<div key={`${item.title}-${index}`} className="border-b border-neutral-200">
<button
type="button"
className="flex w-full items-center justify-between py-5 text-left text-2xl"
onClick={() => setOpenIndex(isOpen ? null : index)}
aria-expanded={isOpen}
>
<span>{item.title}</span>
<span>{isOpen ? "−" : "+"}</span>
</button>
{isOpen && (
<div className="pb-5">
{item.body ? <p className="max-w-[42ch] text-neutral-600">{item.body}</p> : null}
{item.linkLabel && item.linkHref ? (
<a className="mt-3 inline-block underline" href={item.linkHref}>
{item.linkLabel}
</a>
) : null}
</div>
)}
</div>
);
})}
</div>
);
}
Prentice L. "No More Dead Websites" | Web Acceessbility Evangelist | API
Integration & Automation (REST, GraphQL, Webhooks) | CRM, CMS Systems
Specialist | Shopify Store Developer