Skip to main content
Neighborhood Design System v5.0.0-rc.2

Extending components

Compose, wrap and build on components in ways that keep working when Neighborhood updates.

Sometimes a page needs more than one component on its own: a promo strip, a repeated section pattern, a widget only one site needs. You can build these from Neighborhood without changing it, as long as you build on its public API.

What you can build on

Each component’s public API is listed on its component page. Use it freely; Neighborhood keeps it stable within a major version, and the changelog lists any change.

  • Properties and attributes, such as variant and surface.
  • Slots, for the content you put inside.
  • Events, which start with nbhd-.
  • CSS custom properties, which start with --nbhd-.
  • CSS parts, styled with ::part().

These aren’t part of the API and can change in any release:

  • The elements and class names inside a component’s shadow DOM.
  • Custom properties with an underscore, such as --nbhd-_card-overlay-display.
  • Files inside the packages’ dist/ and types/ folders, other than the stylesheets and the bundle named in Installation.

Compose components

Most new patterns are existing components arranged together. Container, Flex and Text cover layout and type, and the section components bring the rest:

<nbhd-container surface="secondary">
  <nbhd-flex split align-items="center">
    <nbhd-text tag="h2" variant="title">Free shipping on orders over $99</nbhd-text>
    <nbhd-cta href="/shipping" variant="secondary">See details</nbhd-cta>
  </nbhd-flex>
</nbhd-container>

Layout and responsive covers Container and Flex in more detail.

Wrap components for your project

When a site repeats the same pattern, wrap it once so every page uses it the same way. The wrapper fixes the settings and takes only the content.

In React:

'use client';

import { NbhdCta, NbhdHeadlineContent, NbhdText } from '@fbin-web/neighborhood-react';

export function PromoBanner({ eyebrow, title, ctaLabel, ctaHref }) {
  return (
    <NbhdHeadlineContent surface="inverse" marginBottom="medium">
      {eyebrow && <NbhdText slot="eyebrow" tag="div" variant="eyebrow">{eyebrow}</NbhdText>}
      <NbhdText slot="title" tag="h2" variant="title">{title}</NbhdText>
      <NbhdCta slot="cta" href={ctaHref}>{ctaLabel}</NbhdCta>
    </NbhdHeadlineContent>
  );
}

On other platforms, the same idea is a template partial: a Shopify section, a Nunjucks macro or a Liquid snippet that outputs the component markup with your settings.

Leave out a prop rather than passing undefined. The React wrappers apply every prop they’re given, so undefined replaces the component’s default.

Respond to events

Components report what happens through nbhd-* events, with details on event.detail:

document.querySelector('nbhd-pagination').addEventListener('nbhd-page-changed', (event) => {
  loadResults(event.detail.page);
});

In React, each event has an onNbhd* prop, such as onNbhdPageChanged. Each component page lists its events.

Properties that take lists or objects, such as the options of a Select, are set in JavaScript rather than as attributes:

document.querySelector('nbhd-select').items = [
  { name: 'Matte Black', value: 'matte-black' },
  { name: 'Chrome', value: 'chrome' },
];

Use components in forms

Input, Textarea, Checkbox, Radio, Radio Group, Select, Range and Upload work inside a native <form>, like the browser’s own fields:

  • They submit their value under their name. A multiple Select and an Upload send one entry per value or file.
  • They reset to their starting value with the form, and a disabled <fieldset> disables them.
  • They validate. required and the native rules (an email type, pattern, min, max, length) block submission and show the browser’s message on the field. invalid doesn’t: it only shows the error state and error-text, for your framework to set. To block submission yourself, call setCustomValidity(message), and setCustomValidity('') to clear it. Pressing Enter in an Input clicks the form’s first submit button, as in a native form (so its name, value and formaction apply), unless a key handler calls preventDefault().
  • They have the browser’s validation methods: checkValidity(), reportValidity(), setCustomValidity(), validity and validationMessage.
<form action="/subscribe" method="post">
  <nbhd-input name="email" type="email" label="Email" required></nbhd-input>
  <nbhd-checkbox name="consent" value="yes" label="Send me product news" required></nbhd-checkbox>
  <nbhd-button type="submit">Subscribe</nbhd-button>
</form>

Read values from the form, with new FormData(form), rather than copying them into hidden inputs. Hidden copies would now be sent twice.

Build your own

When nothing in Neighborhood fits and the need is specific to one site, build the piece in your project. Make it feel like part of the system:

  • Use tokens for every color, size and font. See Working with tokens.
  • Use the context color tokens for text, so it follows the surface it sits on.
  • Use logical properties, such as margin-block-end and padding-inline. See Styling.
  • Use Neighborhood components inside it for buttons, links, text and media, rather than restyling plain elements.
  • Don’t use the nbhd- prefix for your own custom elements or classes. It’s reserved for Neighborhood.

When to ask instead

If a pattern would be useful on more than one site or brand, ask for it in Neighborhood instead of building it locally. It gets built once, works on every brand and gets fixes for everyone. Request a change or a new component.

Stay upgrade-safe

Before updating the Neighborhood packages:

  • Read the changelog for the versions you’re moving to.
  • Check pages that use Draft components; their APIs can change in any release.
  • Search your code for underscore properties (--nbhd-_) and deep dist/ imports, and replace them with public options.
Esc
↑ ↓ to move↵ to open