Build your home page

Your home page is one HTML file, src/custom/site/home.html: a whole page with your own styles, scripts and animation. Arc CMS fills in the live parts (your header and footer, cards from your content, your contact details, signup and contact forms) and publishes it as a fast static page in every language, with everything search engines and AI assistants read.

Until you write one

Arc CMS's own home page (public/_site/home.html) is a placeholder: "This site is not set up yet". It tells search engines not to list it. Your file replaces it.

Write it

  1. Start from an example, or from your designer's page. docs/examples/arc-cms-home.html is Arc CMS's own marketing page written this way; copy it to src/custom/site/home.html and its stylesheet and script, docs/examples/arc-cms-home.css and docs/examples/arc-cms-home.js, to src/custom/site/assets/.

  2. Keep it a whole document: <head> with your <title>, <meta name="description">, fonts and stylesheets, then <body>. Any HTML works; there are no special rules for {, } or @.

  3. Put your own files in src/custom/site/assets/; they are served at /site/. Link them as /site/home.css, /site/home.js, /site/hero.webp. Arc CMS adds each file's version to those links (/site/home.css?v=…), in your pages and in the url() of your stylesheets, so a changed file reaches visitors whose browser kept the old one.

  4. Run npm run dev and open /. The page is shown from your file, live parts included; save the file and reload.

<!doctype html>
<html lang="en">
<head>
    <title>Deepakam: Sanskrit for kids</title>
    <meta name="description" content="Short daily Sanskrit lessons for children.">
    <link rel="stylesheet" href="/site/home.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js" defer></script>
</head>
<body>
    <arc-header></arc-header>
    <section class="hero">
        <h1 data-arc-t="home_heading">Sanskrit for the whole family</h1>
        <button data-arc-install hidden>Install the app</button>
        <a href="/learn" data-arc-signed-in hidden>Open the app</a>
    </section>
    <arc-content-partials content-type="articles" count="3" section-title="From the blog"></arc-content-partials>
    <form data-waitlist-form data-waitlist-id="waitlist-form">
        <input name="email" type="email" placeholder="Your email">
        <button type="submit">Join</button>
    </form>
    <arc-footer></arc-footer>
    <script src="/site/home.js" defer></script>
</body>
</html>

The live parts

WriteBecomes
<arc-header></arc-header>, <arc-footer></arc-footer>Your site header and footer (see Design templates)
<arc-content-partials content-type="articles">Cards of that type's items, newest first or in the type's own order, laid out by its partials.html. count (default 4), section-title (default "Latest" and the type's name, or the page's latest_of_type string) and template-folder (another folder's cards) are optional. A type without public pages works too, for services, a hero or testimonials that editors change: its cards have no links (see Let editors change your home page). The page is republished when that type's content is published, unpublished or arranged.
<arc-search>, <arc-language-switcher>The search box and the language links, outside the header too
<form data-waitlist-form data-waitlist-id="…">A signup form: the emailed code, then a short confirmation (see Collect sign-ups). The terms notice is added above its button.
<form data-arc-contact-form>A contact form whose messages land in Messages in the admin (see Contact form). A privacy line is added above its button.
data-arc-site="phone", data-arc-site-loop="social"The site's name, email, phone, address, logo, social links and the year, from Settings, About (see Site info). Works here, in the header and footer, templates and static pages.
<span data-waitlist-count="…"></span>The number of confirmed sign-ups on that form
<button data-arc-install hidden>Shown when the browser offers installing your app; a click asks. Needs the installable app on (see Make it installable). In your script, window.arcSite.install() and window.arcSite.canInstall do the same.
data-arc-signed-in, data-arc-signed-outElements shown to people signed in to the app on this browser, or to everyone else. Give the signed-in one hidden so it starts hidden. In your script, window.arcSite.signedIn says the same, and <html> has the class arc-signed-in (see Signed in, in your own script).
data-arc-t="key"Text in the page's language (below)

Signed in, in your own script

The app keeps a hint on this browser of whether someone is signed in: the local storage key arc:signed-in is '1' while someone is, and absent otherwise. The key and its value are stable, so a page's own script can read them, including an inline script at the top of the page that runs before arc-site.js. For example, a home page that sends someone signed in straight to the app's main screen:

<script>
    try {
        if (localStorage.getItem('arc:signed-in') === '1') location.replace('/learn');
    } catch (e) { /* storage off: stay on the page */ }
</script>

It is a hint, not a sign-in: it holds no identity and grants nothing, and it can be out of date (someone signed out in another tab, or their account was deleted). The app's own pages still check the real sign-in, so the worst a stale hint does is open the app's sign-in page, which forwards a signed-in person on. After arc-site.js has run, window.arcSite.signedIn has the same answer.

Styles, scripts and animation

Your stylesheets and scripts are yours. Arc CMS's stylesheets (Bootstrap, main.css and your src/custom/site/site.css) are linked before them, so your rules win. main.css styles only the page body and the site header and footer, so your class names are free. Scripts are plain files: load a library such as GSAP or ScrollTrigger from a CDN, or keep its file in src/custom/site/assets/, and write your own in /site/home.js. A script cannot import an npm package, because the page is served as it is, without a build step.

Start animations when the page has loaded, for example with defer on your script tag. On the live site your scripts run as the browser normally runs them.

In npm run dev the app shows the page, and it adds your scripts only after the page has loaded. Scripts with a src then run as each one arrives, in no fixed order, so home.js may run before the library it uses, and code that waits for DOMContentLoaded never runs. Wait for the library in your script, and check document.readyState before waiting for the page. The app's own styles are also on the page in npm run dev, but not on the live site, so check the look on the live site before launch.

An address your script builds itself, such as fetch('/site/words.json'), gets no version, and a returning visitor's browser may keep the old file for a year. Fetch it with { cache: 'no-cache' }, or give the file a new name when it changes.

What Arc CMS adds when it publishes

These are always set for the page's language, and replace any your page has: <html lang> (with dir="rtl" for a right-to-left language), the canonical address, og:url, og:locale and the links to the other languages (hreflang).

These are added only where your page has none: a title and description (from Settings, About), the other Open Graph and Twitter tags (the logo from About as the image), <meta name="robots" content="index, follow">, and the app manifest when the installable app is on. Your own title, description and social tags are kept.

Arc CMS also adds the site's structured data (Organization and WebSite) and the small script that runs the live parts (/assets/js/arc-site.js), which every published page carries, so a form works on any of them. The home page is listed in the sitemap in every language.

While the setup wizard is not finished, that script sends visitors to /onboarding, as the app does: everyone on a fresh install, and only people signed in once someone has started the setup. Add ?debug to the address to stay on the page.

More than one language

The home page is published at / and at /{lang} for every language you turn on (see Publish in more than one language). For each language it uses:

docs/examples/arc-cms-home.hi.html is the example page in Hindi, written as a whole page. Copy it to src/custom/site/home.hi.html to see how one looks.

Links to pages that exist in every language point at the page's language: the home page (/ becomes /hi), search and your content types (/articles becomes /hi/articles). Everything else exists once and keeps its address: sign-in, the member area, your app's own pages (/learn), static pages (/p/…) and files (/site/…, /assets/…).

Put it live

Deploy the website with npm run deploy and choose Website or Everything (see Deploy). The deploy keeps the pages already published, then publishes every page again, the home page included. After that, the home page is published again by itself when content it shows is published, unpublished or arranged, and when you save a setting it uses: About, the site address, the languages, or the powered-by setting. When your header, footer, templates or static pages print About's details with data-arc-site, saving About publishes the whole site again.

To publish the whole site again yourself, open Content, Content types and choose Republish website. It rebuilds every content page and list page, the home page, the static pages, the sitemap and the feeds, in one release, from the files on the live site.

The live site serves the published page. A change to home.html shows in npm run dev at once, but reaches the live site only after a website deploy. Publishing reads the live site's files, not yours: while your site files differ from the live ones, the content editor and Content types say Live site differs (only in npm run dev; hover for the files, or click it for the message; on a phone the editor shows only the warning icon, which you tap).

Next

Let editors change the services, hero, questions and contact details without touching HTML: Let editors change your home page.