Skip to main content
Neighborhood Design System v5.1.0

Platform setup

Set up Neighborhood on Next.js, Vite, Vue, Svelte, Angular, static sites, Shopify and Bloomreach.

Neighborhood works the same way on every platform. Each page needs three things:

  1. The components, from the core package or its self-contained bundle.
  2. One brand stylesheet, with its fonts.
  3. Markup that places the components and fills their slots with content.

What changes from platform to platform is how those files reach the page and how content gets into the markup. Installation covers the packages and files; this page covers each platform.

With a bundler or without

Your platform Components Brand stylesheet
Has a bundler (Next.js, Vite, webpack) import from @fbin-web/neighborhood-core or @fbin-web/neighborhood-react import the brand’s all.css
No bundler (static sites, CMS templates) A script tag for @fbin-web/neighborhood-core/build/library/neighborhood.js A link tag for the brand’s all.css, or its token file if the site loads the fonts itself

The build/library/neighborhood.js file is self-contained, so it runs from a script tag with nothing else installed. Brand stylesheets load their fonts from a fonts/ folder next to them, so copy the brand’s whole folder, not just the CSS file.

Next.js

  1. Install the React, core and brands packages, as in Installation.

  2. Import the brand stylesheet once, in your root layout or global CSS:

    /* app/globals.css */
    @import '@fbin-web/neighborhood-brands/dist/moen/neighborhood.moen.all.css';
  3. Render Neighborhood components from Client Components. They depend on the browser, so files that use them start with 'use client':

    'use client';
    
    import { NbhdCta, NbhdHeadlineContent, NbhdText } from '@fbin-web/neighborhood-react';
    
    export function Intro() {
      return (
        <NbhdHeadlineContent>
          <NbhdText slot="title" tag="h1" variant="title">Faucets made for everyday</NbhdText>
          <NbhdCta slot="cta" href="/faucets">Shop faucets</NbhdCta>
        </NbhdHeadlineContent>
      );
    }
  4. Put text and media in slots rather than props. Slotted content is in the server-rendered HTML, so it shows before the components load and is visible to search engines. Props are applied once the components load in the browser.

No changes to next.config are needed. React covers events, refs and forms.

React with Vite

Install the React, core and brands packages, import the brand stylesheet in your app’s entry file, and import components from @fbin-web/neighborhood-react. Quick start walks through it from a new project, and React covers the details.

Vue, Svelte and Angular

These frameworks use the Web Components directly, from @fbin-web/neighborhood-core; there are no wrappers. The steps below come from working demos built with Vite and Vue 3.5, Vite and Svelte 5, and Angular 22. They aren’t part of regular release testing, so check your own setup against Storybook.

Whichever framework you use, the same rules apply:

  • Register the components before the app starts. Import @fbin-web/neighborhood-core first in your entry file. Each framework checks whether an element has a property before deciding to set a property or an attribute, so the element must already be defined.
  • Fill slots with slot attributes, as in plain HTML.
  • Pass lists and objects as properties, such as the items of a Select. Attributes can only hold strings.
  • Listen for nbhd-* events with the framework’s own event syntax, and read the value from event.detail.
  • Two-way binding doesn’t apply. Set value and update it from nbhd-change, instead of v-model or [(ngModel)].
  • Forms submit natively. Read the values with new FormData(form). See Use components in forms.

Server rendering, in Nuxt, SvelteKit or Angular SSR, isn’t covered by the demos. Load Neighborhood only in the browser, and put content that must be in the first HTML in slots.

Vue

  1. Install the core and brands packages:

    npm install @fbin-web/neighborhood-core @fbin-web/neighborhood-brands
  2. Tell Vue that nbhd-* tags are custom elements, so it doesn’t look for Vue components with those names:

    // vite.config.js
    import { defineConfig } from 'vite';
    import vue from '@vitejs/plugin-vue';
    
    export default defineConfig({
      plugins: [
        vue({
          template: {
            compilerOptions: { isCustomElement: (tag) => tag.startsWith('nbhd-') },
          },
        }),
      ],
    });
  3. Load the brand stylesheet and the components before the app mounts:

    // src/main.js
    import '@fbin-web/neighborhood-brands/dist/moen/neighborhood.moen.all.css';
    import '@fbin-web/neighborhood-core';
    
    import { createApp } from 'vue';
    import App from './App.vue';
    
    createApp(App).mount('#app');
  4. Use the components in templates. :items sets a property, and @nbhd-change listens for the event:

    <nbhd-select
      name="finish"
      label="Finish"
      :items="finishes"
      @nbhd-change="finish = $event.detail.value"></nbhd-select>

Svelte

  1. Install the core and brands packages, as for Vue. Svelte needs no configuration: it treats any tag with a hyphen as a custom element.

  2. Load the brand stylesheet and the components before the app mounts:

    // src/main.js
    import '@fbin-web/neighborhood-brands/dist/moen/neighborhood.moen.all.css';
    import '@fbin-web/neighborhood-core';
    
    import { mount } from 'svelte';
    import App from './App.svelte';
    
    mount(App, { target: document.getElementById('app') });
  3. Use the components in your markup. Event handlers are on followed by the event name:

    <nbhd-select
      name="finish"
      label="Finish"
      items={finishes}
      onnbhd-change={(event) => (finish = event.detail.value)}></nbhd-select>

Angular

  1. Install the core and brands packages, as for Vue.

  2. Add the brand stylesheet to styles in angular.json:

    "styles": ["@fbin-web/neighborhood-brands/dist/moen/neighborhood.moen.all.css"]
  3. Register the components first in src/main.ts:

    import '@fbin-web/neighborhood-core';
    
    import { provideZonelessChangeDetection } from '@angular/core';
    import { bootstrapApplication } from '@angular/platform-browser';
    import { App } from './app/app';
    
    bootstrapApplication(App, { providers: [provideZonelessChangeDetection()] });
  4. Add CUSTOM_ELEMENTS_SCHEMA to each component that uses Neighborhood, so Angular accepts the tags:

    import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
    
    @Component({
      selector: 'app-root',
      schemas: [CUSTOM_ELEMENTS_SCHEMA],
      templateUrl: './app.html',
    })
    export class App {
      onFinishChange(event: Event) {
        const { value } = (event as CustomEvent<{ value: string }>).detail;
      }
    }
  5. Use a [property] binding for anything that isn’t a string, and (event) for events. With CUSTOM_ELEMENTS_SCHEMA, $event is typed as Event, so cast it to read detail:

    <nbhd-select
      name="finish"
      label="Finish"
      [items]="finishes"
      (nbhd-change)="onFinishChange($event)"></nbhd-select>

Static sites and Eleventy

Copy the files from node_modules into your site’s output, then reference them in your page layout. In Eleventy, passthrough copy does this on every build:

// eleventy.config.js
eleventyConfig.addPassthroughCopy({
  './node_modules/@fbin-web/neighborhood-core/build/library/neighborhood.js': 'js/neighborhood.js',
  './node_modules/@fbin-web/neighborhood-brands/dist/moen': 'css/moen',
});
<head>
  <link rel="stylesheet" href="/css/moen/neighborhood.moen.all.css" />
  <script type="module" src="/js/neighborhood.js"></script>
</head>

Other static site generators work the same way: copy the bundle and the brand folder, then link them.

Shopify

Shopify themes have no bundler, so use the self-contained files.

  1. Upload the assets. Add build/library/neighborhood.js and the brand’s token file (neighborhood-tokens/dist/brands/neighborhood.tokens.<brand>.css) to the theme’s assets folder.

  2. Load them in the layout. Add this before the closing </head> in each layout that uses Neighborhood:

    <script type="module" src="{{ 'neighborhood.js' | asset_url }}"></script>
    <link rel="stylesheet" href="{{ 'neighborhood.tokens.moen.css' | asset_url }}">
  3. Load the brand fonts. Shopify’s assets folder is flat, so the brand’s font files can’t keep their fonts/ folder. Upload the font files to assets, and load them with a font stylesheet saved as a .css.liquid file that points to each font with asset_url.

  4. Build sections from components. In each section, settings become component attributes and text settings fill slots:

    <nbhd-headline-content surface="{{ section.settings.surface }}">
      <nbhd-text slot="title" tag="h2" variant="title">{{ section.settings.title }}</nbhd-text>
      <nbhd-cta slot="cta" href="{{ section.settings.cta_url }}">{{ section.settings.cta_label }}</nbhd-cta>
    </nbhd-headline-content>

    Repeating content, such as the cards in a Card List, becomes section blocks, with one component for each block.

Bloomreach

In Bloomreach, each Neighborhood component becomes a content type plus a component definition, following the content model:

  • Slots become content type fields. Eyebrows and titles are text fields, body copy is rich text, calls to action share a CTA field group, and images and video share a media field group.
  • Properties become component parameters. Booleans become toggles and fixed-value properties such as surface become dropdowns.
  • Repeating content, such as cards in a Card List, becomes a repeatable field group with its own content type.

Neighborhood can generate these content type and component definitions for any component. Request them for the components your site uses.

Other libraries on the page

Neighborhood components keep their styles inside a shadow DOM, so other CSS on the page, such as Bootstrap, Tailwind or a theme’s own styles, can’t change their internals. Page-wide styles can still affect the content you put in slots, because that content is part of your page. If a library’s styles change how slotted text or links look, scope the library’s styles away from Neighborhood sections, and mention the library when you report a bug.

Esc
↑ ↓ to move↵ to open