diff --git a/packages/fast-element/docs/building-components.md b/packages/fast-element/docs/building-components.md index 92b8466dcb5..ad8b2ce665a 100644 --- a/packages/fast-element/docs/building-components.md +++ b/packages/fast-element/docs/building-components.md @@ -64,7 +64,7 @@ By default, any attribute created with `@attr` will perform no explicit type coe * `reflect` - The *default* mode that is used if none is specified. This reflects property changes to the DOM. If a `converter` is supplied, it will invoke the converter before calling the `setAttribute` DOM API. * `boolean` - This mode causes your attribute to function using the HTML boolean attribute behavior. When your attribute is present in the DOM or equal to its own name, the value will be true. When the attribute is absent from the DOM, the value of the property will be false. Setting the property will also update the DOM by adding/removing the attribute. -* `none` - This mode skips reflecting the value of the property back to the HTML attribute, but does receive updates when changed through `setAttribute`. +* `fromView` - This mode skips reflecting the value of the property back to the HTML attribute, but does receive updates when changed through `setAttribute`. In addition to setting the `mode`, you can also supply a custom `ValueConverter` by setting the `converter` property of the attribute configuration. The converter must implement the following interface: @@ -78,7 +78,7 @@ interface ValueConverter { Here's how it works: * When the DOM attribute value changes, the converter's `fromView` method will be called, allowing custom code to coerce the value to the proper type expected by the property. -* When the property value changes, the converter's `fromView` method will also be called, also ensuring that the type is correct. After this, the `mode` will be determined. If the mode is set to `reflect` then the converter's `toView` method will be called to allow the type to be formatted before writing to the attribute using `setAttribute`. +* When the property value changes, the converter's `fromView` method will also be called, ensuring that the type is correct. After this, the `mode` will be determined. If the mode is set to `reflect` then the converter's `toView` method will be called to allow the type to be formatted before writing to the attribute using `setAttribute`. > **NOTE:** When the `mode` is set to `boolean`, a built-in `booleanConverter` is automatically used to ensure type correctness so that manual configuration of the converter is not needed in this common scenario. @@ -194,7 +194,7 @@ There are several important details in the above example, so let's break them do First, we create a template by using a [tagged template literal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals). The tag, `html`, provides special processing for the HTML string that follows, returning an instance of `HTMLTemplate`. Your templates can be *typed* to the data model that they are rendering over. In TypeScript, we simply provide the type as part of the tag: `html`. -Within a template, we provide *expressions* that declare the *dynamic parts* of our template. These expressions are declared with [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions). Because the template is typed, the input to your arrow function will be an instance of the data model you delcared in your `html` tag. When the `html` tag processes your template, it identifies these dynamic expressions and builds up an optimized model, capable of high-performance rendering, and efficient, incremental batched updates. +Within a template, we provide *expressions* that declare the *dynamic parts* of our template. These expressions are declared with [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions). Because the template is typed, the input to your arrow function will be an instance of the data model you declared in your `html` tag. When the `html` tag processes your template, it identifies these dynamic expressions and builds up an optimized model, capable of high-performance rendering, and efficient, incremental batched updates. Finally, we associate the template with our custom element by using a different from of the `@customElement` decorator, which allows us to pass more options. In this configuration, we pass an options object specifying the `name` and the `template`. @@ -229,19 +229,19 @@ To bind the content of an element, simply provide the expression within the star ``` -> **NOTE:** Dynamic content is set via the `textContent` HTML property. You *cannot* set HTML content this way. See below for the explicit, opt-in mechanism for setting HTML. +> **NOTE:** Dynamic content is set via the `textContent` HTML property for security reasons. You *cannot* set HTML content this way. See below for the explicit, opt-in mechanism for setting HTML. -#### Dynamic Properties +#### Dynamic Attributes -You can also use an expression to set a property on an HTML element. Simply place the expression where the value of the HTML attribute would normal go. The template engine will map your attribute to the element's property and set it with the value of your expression. +You can also use an expression to set an attribute value on an HTML Element. Simply place the expression where the value of the HTML attribute could go. The template engine will then use your expression to set the value using `setAttribute(...)`, whenever it needs to be updated. Additionally, some attributes are known as [boolean attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes#Boolean_Attributes) (e.g. required, readonly, disabled). These attributes behave differently from normal attributes, and need special value handling. The templating engine will handle this for you if you prepend the attribute name with a `?`. -**Example: Basic Property Values** +**Example: A Basic Attribute Values** ```HTML x.aboutLink}>About ``` -**Example: Interpolated Property Values** +**Example: Interpolated Attribute Values** ```HTML @@ -261,37 +261,45 @@ You can also use an expression to set a property on an HTML element. Simply plac ``` -**Example: Inner HTML** +**Example: ARIA Attributes** ```HTML -
sanitize(x.someDangerousHTMLContent)}>
+
+
``` -> **WARNING:** Avoid scenarios that require you to directly set HTML, especially when the content is coming from an external source. If you must do this, always sanitize the HTML content using a robust HTML sanitizer library, represented by the use of the `sanitize` function above. +**Example: Boolean Attributes** -#### Dynamic Attributes +```HTML + +``` -Most HTML attributes have a corresponding property on the HTML element itself, so the method of property binding described above will be the most common mechanism used. However, there are some scenarios, such as with [ARIA attributes](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA), where there is no corresponding element property. For these scenarios, prepend a `$` to the attribute name, and the value will be set with the `setAttribute` API instead of through a property. Additionally, some attributes are known as [boolean attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes#Boolean_Attributes) (e.g. required, readonly, disabled). These attributes behave differently from normal attributes, and need special value handling. The templating engine will handle this for you if you prepend the attribute name with a `?`. +#### Dynamic Properties -**Example: ARIA Attributes** +Properties can also be set directly on an HTML element. To do so, prepend the property name with `:` to indicate a property binding. The template engine will then use your expression to assign the element's property value. + +**Example: Basic Property Values** ```HTML -
-
+ x.mySpecialData}> + ... + ``` -**Example: Boolean Attributes** +**Example: Inner HTML** ```HTML - +
sanitize(x.someDangerousHTMLContent)}>
``` +> **WARNING:** Avoid scenarios that require you to directly set HTML, especially when the content is coming from an external source. If you must do this, always sanitize the HTML content using a robust HTML sanitizer library, represented by the use of the `sanitize` function above. + #### Events -Besides rendering content, properties, and attributes, you'll often want to add event listeners and execute code when events fire. To do that, prepend the event name with `@` and provide the expression to be called when that event fires. Within an event expression, you also have access to a special *context* argument from which you can access the event args. +Besides rendering content, attributes, and properties, you'll often want to add event listeners and execute code when events fire. To do that, prepend the event name with `@` and provide the expression to be called when that event fires. Within an event expression, you also have access to a special *context* argument from which you can access the event args. **Example: Basic Events** @@ -303,11 +311,13 @@ Besides rendering content, properties, and attributes, you'll often want to add ```HTML + :value="${x => x.description}" + @input="${(x, c) => x.handleDescriptionChange(c.event)}"> ``` -> **IMPORTANT:** The templating engine only supports *unidirectional data flow* (model => view). It does not support *two-way data binding* (model <=> view). As shown above, pushing data from the view back to the model should be handled with explicit events that call into your model's API. +In both examples above, after your event handler is executed, `preventDefault()` will be called on the event object by default. You can return `true` from your handler to opt out of this behavior. + +The second example demonstrates an important characteristic of the templating engine: it only supports *unidirectional data flow* (model => view). It does not support *two-way data binding* (model <=> view). As shown above, pushing data from the view back to the model should be handled with explicit events that call into your model's API. ### Using Directives @@ -320,8 +330,7 @@ Sometimes you need a direct reference to a DOM node from your template. This mig **Example: Referencing an Element** ```TypeScript -import { FastElement, customElement, attr, html } from '@microsoft/fast-element'; -import { ref } from '@microsoft/fast-element/directives/ref'; +import { FastElement, customElement, attr, html, ref } from '@microsoft/fast-element'; const template = html`