AttributeMarshallingMixin

Sets properties when the corresponding attributes change

Overview

Purpose: maps element attributes to component properties.

This mixin works at the beginning of the Elix render pipeline:

eventsmethods → setState → render DOM → post-render

Expects the component to provide:

  • Property getter/setters for all properties that correspond to attributes.

Provides the component with:

  • attributeChangedCallback implementation that maps attribute changes to property changes.
  • observedAttributes implementation that, by default, indicates the component wants to receive attribute change notifications for all attributes corresponding to the component's custom properties.

This mixin's function is so common that it is included in the Elix base class ReactiveElement.

Usage

import AttributeMarshallingMixin from "elix/src/core/AttributeMarshallingMixin.js";
class MyElement extends AttributeMarshallingMixin(HTMLElement) {}

Example

This sample component defines a custom fooBar property, then exposes it as a "foo-bar" attribute:

const fooBarSymbol = Symbol("fooBar");

class MyElement extends AttributeMarshallingMixin(HTMLElement) {
  get fooBar() {
    return this[fooBarSymbol];
  }
  set fooBar(value) {
    this[fooBarSymbol] = value;
  }
}

customElements.define("my-element", MyElement);

Because the component applies AttributeMarshallingMixin, the camelCase fooBar property can be set in markup via the hyphenated "foo-bar" attribute:

<my-element foo-bar="Hello"></my-element>

When this element is instantiated, the fooBar property setter will automatically be invoked with the initial value "Hello".

attributeChangedCallback

This mixin provides a default attributeChangedCallback implementation that will convert a change in an element attribute into a call to the corresponding property setter.

Attributes typically follow hyphenated names ("foo-bar"), whereas properties typically use camelCase names ("fooBar"). This mixin respects that convention, automatically mapping the hyphenated attribute name to the corresponding camelCase property name and invoking the indicated property setter.

Attributes can only have string values, so a string value is what is passed to the property setter. If you'd like to convert string attributes to other types (numbers, booleans), you must implement parsing yourself in the property setter. For example, the following code implements a Boolean property that can be set as either: a) a Boolean value or b) a string representing a Boolean value:

get foo() {
  return this[internal.state].foo;
}
set foo(foo) {
  const parsed = String(foo) === 'true'; // Cast to Boolean
  this[internal.setState]({ foo: parsed });
}

observedAttributes

AttributeMarshallingMixin provides a default implementation of the static observedAttributes property. When you register your component with the browser, the browser will get the value of this observedAttributes property to determine which attributes the component wishes to monitor for changes. Changes in those attributes will trigger an attributeChangedCallback call.

Because maintaining the mapping of attributes to properties is tedious, AttributeMarshallingMixin provides a default implementation for observedAttributes. This implementation assumes that your component will want to expose all public properties in your component's API as properties. E.g., in the above example, the component defines a camelCase property called fooBar, so the default value of observedAttributes will automatically include an entry for the kebab-case attribute name, "foo-bar".

You can override this default implementation of observedAttributes. For example, if you have a system that can statically analyze which properties are available to your component, you could hand-author or programmatically generate a definition for observedAttributes that avoids the minor run-time performance cost of determining your component's public properties.

API

Used by classes AlertDialog, AutoCompleteComboBox, AutoCompleteInput, AutoSizeTextarea, Backdrop, Button, CalendarDay, CalendarDayButton, CalendarDayNamesHeader, CalendarDays, CalendarMonth, CalendarMonthNavigator, CalendarMonthYearHeader, Carousel, CarouselSlideshow, CarouselWithThumbnails, CenteredStrip, CheckListItem, ComboBox, CrossfadeStage, DateComboBox, DateInput, Dialog, Drawer, DrawerWithGrip, DropdownList, ExpandablePanel, ExpandableSection, Explorer, FilterComboBox, FilterListBox, HamburgerMenuButton, Hidden, Input, ListBox, ListComboBox, ListExplorer, ListWithSearch, Menu, MenuButton, MenuItem, MenuSeparator, ModalBackdrop, Modes, MultiSelectListBox, NumberSpinBox, Option, OptionList, Overlay, OverlayFrame, PlainAlertDialog, PlainArrowDirectionButton, PlainAutoCompleteComboBox, PlainAutoCompleteInput, PlainAutoSizeTextarea, PlainBackdrop, PlainBorderButton, PlainButton, PlainCalendarDay, PlainCalendarDayButton, PlainCalendarDayNamesHeader, PlainCalendarDays, PlainCalendarMonth, PlainCalendarMonthNavigator, PlainCalendarMonthYearHeader, PlainCarousel, PlainCarouselSlideshow, PlainCarouselWithThumbnails, PlainCenteredStrip, PlainCenteredStripHighlight, PlainCenteredStripOpacity, PlainChoice, PlainComboBox, PlainCrossfadeStage, PlainDateComboBox, PlainDateInput, PlainDialog, PlainDrawer, PlainDrawerWithGrip, PlainDropdownList, PlainExpandablePanel, PlainExpandableSection, PlainExpandCollapseToggle, PlainExplorer, PlainFilterComboBox, PlainFilterListBox, PlainHamburgerMenuButton, PlainHidden, PlainInput, PlainListBox, PlainListComboBox, PlainListExplorer, PlainListWithSearch, PlainMenu, PlainMenuButton, PlainMenuItem, PlainMenuSeparator, PlainModalBackdrop, PlainModes, PlainMultiSelectListBox, PlainNumberSpinBox, PlainOptionList, PlainOverlay, PlainOverlayFrame, PlainPageDot, PlainPopup, PlainPopupButton, PlainPopupSource, PlainProgressSpinner, PlainPullToRefresh, PlainRepeatButton, PlainSelectableButton, PlainSlideshow, PlainSlideshowWithPlayControls, PlainSlidingPages, PlainSlidingStage, PlainSpinBox, PlainTabButton, PlainTabs, PlainTabStrip, PlainToast, Popup, PopupButton, PopupSource, ProgressSpinner, PullToRefresh, ReactiveElement, RepeatButton, SelectableButton, Slideshow, SlideshowWithPlayControls, SlidingPages, SlidingStage, SpinBox, TabButton, Tabs, TabStrip, Toast, UpDownToggle, and WrappedStandardElement.