Designed for components, not schemas

Give your marketing team the power of components and composition.

Build React components, not Makeswift components

Icon

Composable controls. Map UI controls to any JSON prop types.

Code example with Makeswift controls UI
Icon

Decoupled components. Makeswift sits outside of your components so you can use them in code or visually.

import React, { ReactNode, Ref, forwardRef } from 'react'

// import { Makeswift } from 'makeswift@runtime'

import * as Accordion from '@radix-ui/react-accordion'
import clsx from 'clsx'

import { Warning } from '../Warning'

type AccordionItem = {
  title: ReactNode
  body: ReactNode
}

type Props = {
  className?: string
  accordions: AccordionItem[]
  type: 'single' | 'multiple'
}

export const Accordions = forwardRef(function Accordions(
  { className, accordions, type = 'multiple' }: Props,
  ref: Ref<HTMLDivElement>
) {
  return (
    <Accordion.Root type={type} ref={ref} className={clsx(className)}>
      {accordions.length === 0 ? (
        <Warning>
          <p className="text-center font-light">There are no Accordions. Try adding some.</p>
        </Warning>
      ) : (
        <ul className="relative w-full after:absolute after:inset-x-0 after:top-0 after:h-[1px] after:bg-gradient-to-r after:from-foreground/0 after:via-foreground after:to-foreground/0 after:opacity-20">
          {accordions.map((accordion, i) => (
            <Accordion.Item key={i} value={`${i + 1}`} asChild>
              <li className="group relative [clip-path:inset(0px_0px)] before:absolute before:left-1/2 before:top-full before:-z-10 before:h-[80px] before:w-3/5 before:-translate-x-1/2 before:-translate-y-1/4 before:rounded-circle before:bg-primary before:opacity-0 before:blur-[100px] before:transition-all before:duration-1000 before:ease-out after:absolute after:inset-x-0 after:bottom-0 after:h-[1px] after:bg-gradient-to-r after:from-foreground/0 after:via-foreground after:to-foreground/0 after:opacity-20 after:mix-blend-overlay after:transition-all after:duration-300 after:ease-linear hover:after:opacity-40 data-[state=open]:before:opacity-100 before:data-[state=open]:delay-200">
                <Accordion.Header>
                  <Accordion.Trigger asChild>
                    <div className="flex w-full cursor-pointer items-center gap-x-8 px-6">
                      <div className="flex-1 py-8 text-left text-lg font-medium leading-normal text-foreground md:text-2xl">
                        {accordion.title}
                      </div>

                      <button className="shrink-0 rounded-circle p-3 ring-1 ring-foreground/20 transition duration-300 ease-in-out group-hover:ring-foreground/40">
                        <svg viewBox="0 0 16 16" className="h-4 w-4 fill-foreground">
                          <rect
                            x="7"
                            className="h-4 w-0.5 origin-center transition-transform duration-300 group-data-[state=open]:rotate-90"
                          />
                          <rect y="7" className="h-0.5 w-4" />
                        </svg>
                      </button>
                    </div>
                  </Accordion.Trigger>
                </Accordion.Header>

                <Accordion.Content className="w-full overflow-hidden data-[state=closed]:animate-collapse data-[state=open]:animate-expand">
                  <div className="text-md px-6 leading-relaxed text-foreground/60 md:pb-8">
                    {accordion.body}
                  </div>
                </Accordion.Content>
              </li>
            </Accordion.Item>
          ))}
        </ul>
      )}
    </Accordion.Root>
  )
})
Icon

No builder-specific wiring. Integrate modals, tabs, accordions, etc. without tightly coupling your component to Makeswift.

Thumbnail of Makeswift builder

Tooling for TypeScript Developers

Icon

Intuitive APIs. Fetch data from Makeswift just like any other CMS. Render it with our open-source components.

import { Makeswift, Page as MakeswiftPage } from '@makeswift/runtime/next'

export async function getStaticPaths() {
  const makeswift = new Makeswift('<makeswift_site_api_key>')
  const pages = await makeswift.getPages()

  return {
    paths: pages.map((page) => ({
      params: { path: page.path.split('/').filter((segment) => segment !== '') },
    })),
    fallback: 'blocking',
  }
}

export async function getStaticProps(ctx) {
  const makeswift = new Makeswift('<makeswift_site_api_key>')
  const path = '/' + (ctx.params?.path ?? []).join('/')
  const snapshot = await makeswift.getPageSnapshot(path, { preview: ctx.preview })

  if (snapshot == null) return { notFound: true }

  return { props: { snapshot } }
}

export default function Page({ snapshot }) {
  return <MakeswiftPage snapshot={snapshot} />
}
Icon

Full type inference. Avoid component integration errors with helpful error messages and autocomplete.

Typescript error popup example
Icon

Integrate in minutes. Use our CLI to quickly scaffold a new project with Makeswift ready to go.

Command line showing Makeswift's CLI

Optimized for Next.js

Icon

ISR and SSG support. Get on-demand revalidation for free with no extra setup.

Icon

Minimal runtime overhead. Progressive hydration keeps performance fast.

Icon

Maintenance free code splitting. Dynamically register all of your components.

Icon

App router support. Coming soon.

Next.js icon with pink lines and circles