Skip to main content Design tokens Components Style utilities
Skip to table of contents

    Form controls

    Every Placer Toolkit component makes use of a shadow DOM to encapsulate markup, styles and behaviour. One caveat of this approach is that native <form> elements do not recognise form controls located inside a shadow root.

    Placer Toolkit solves this problem by using the formdata event, which is available in all modern browsers. This means, when a form is submitted, Placer form controls will automatically append their values to the FormData object that’s used to submit the form. In most cases, things will “just work”. However, if you’re using a form serialisation library, it might need to be adapted to recognise Placer form controls.

    Placer Toolkit uses event listeners to intercept the form’s formdata and submit events. This allows it to inject data and trigger validation as necessary. If you’re also attaching an event listener to the form, you must attach it after Placer form controls are connected to the DOM, otherwise your logic will run before Placer Toolkit has a chance to inject form data and validate form controls.

    Data serialisation

    Serialisation is just a fancy word for collecting form data. If you’re relying on standard form submissions (i.e. <form action="…">), you can probably skip this section. However, most apps use the Fetch API or a library such as Axios to submit forms using JavaScript.

    The FormData interface offers a standard way to serialise forms in the browser. You can create a FormData object from any <form> element like this.

    const form = document.querySelector("form");
    const data = new FormData(form);
    
    // All form control data is available in a FormData object

    However, some people find FormData tricky to work wth or they need to pass a JSON payload to their server. To accommodate this, Placer Toolkit offers a serialisation utility that gathers form data and returns a simple JavaScript object instead.

    import { serialize } from "placer-toolkit/dist/utilities/form.js";
    
    const form = document.querySelector("form");
    const data = serialize(form);
    
    // All form control data is available in a JavaScript object

    This results in an object with name/value pairs that map to each form control. If more than one form control share the same name, the values will be passed as an array (e.g., { name: ["value1", "value2"] }).

    Constraint validation

    Client‐side validation can be enabled through the browser’s Constraint Validation API for Placer form controls. You can activate it using attributes such as required, pattern, minlength, maxlength and so on. Placer Toolkit implements many of the same attributes as native form controls, but check the documentation for a list of supported properties for each component.

    If you don’t want to use client‐side validation, you can suppress this behaviour by adding novalidate to the surrounding <form> element.

    If this syntax looks unfamiliar, don’t worry! Most of what you’re learning on this page is platform knowledge that applies to regular form controls too.

    Client‐side validation can be used to improve the UX of forms, but it is not a replacement for server‐side validation. You should always validate and sanitise user input on the server!

    Required fields

    To make a field required, use the required attribute. Required fields will automatically receive a * after their labels. This is configurable through the --pc-input-required-content custom property.

    This form will not be submitted if a required field is incomplete.

    This code demo is unavailable due to a missing component: Textarea

    Input patterns

    To restrict a value to a specific pattern, use the pattern attribute. This example only allows the letters A–Z, so the form will not submit if a number or symbol is entered. This only works with <pc-input> elements.

    Input types

    Some input types will automatically trigger constraints, such as email and url.

    Custom validation errors

    To create a custom validation error, pass a non‐empty string to the setCustomValidity() method. This will override any existing validation constraints. The form will not be submitted when a custom validity is set and the browser will show a validation error when the containing form is submitted. To make the input valid again, call setCustomValidity() again with an empty string.

    Custom validation can be applied to any form control that supports the setCustomValidity() method. It is not limited to inputs and textareas.

    Custom validation styles

    Due to the many ways form controls are used, Placer Toolkit doesn’t provide out‐of‐the‐box validation styles for form controls as part of its default theme. Instead, the following attributes will be applied to reflect a control’s validity as users interact with it. You can use them to create custom styles for any of the validation states you’re interested in.

    • data-required — The form control is required.
    • data-optional — The form control is optional.
    • data-invalid — The form control is currently invalid.
    • data-valid — The form control is currently valid.
    • data-user-invalid — The form control is currently invalid and the user has interacted with it.
    • data-user-valid — The form control is currently valid and the user has interacted with it.

    The attributes map to the browser’s built‐in pseudo‐classes for validation: :required, :optional, :invalid, :valid, :user-invalid and :user-valid.

    In the future, data attributes will be replaced with custom pseudo‐classes should as :--valid and :--invalid. Placer Toolkit is using data attributes as a workaround until browsers support custom states through ElementInternals.states.

    Styling invalid form controls

    You can target validity using any of the aforementioned data attributes, but it’s usually preferable to target data-user-invalid and data-user-valid since they only get applied after a user interaction such as typing or submitting. This prevents empty form controls from appearing invalid immediately, which results in a poor user experience.

    This example demonstrates custom validation styles using data-user-invalid and data-user-valid. Try typing in the fields to see how validity changes with user input.

    Inline form validation

    By default, Placer form controls use the browser’s tooltip‐style error messages. No mechanism is provided to show errors inline, as there are too many opinions on how that would work when combined with native form controls and other custom elements. You can, however, implement your own solution using the following technique.

    To disable the browser’s error messages, you need to cancel the pc-invalid event. Then you can apply your own inline validation errors. This example demonstrates a primitive way to do this.

    This example is meant to demonstrate the concept of providing your own error messages inline. It is not intended to scale to more complex forms. Users who want this functionality are encouraged to build a more appropriate validation solution using the techniques shown below. Depending on how you implement this feature, custom error messages may affect the accessibility of your form controls.

    Getting associated form controls

    At this time, using HTMLFormElement.elements will not return Placer form controls because the browser is unaware of their status as custom element form controls. Fortunately, Placer Toolkit provides an elements() function that does something very similar. However, instead of return an HTMLFormControlsCollection, it returns an array of HTML and Placer form controls in the order they appear in the DOM.

    import { getFormControls } from "placer-toolkit/dist/utilities/form.js";
    
    const form = document.querySelector("#my-form");
    const formControls = getFormControls(form);
    
    // Example output: [input, pc-input, …]
    console.log(formControls);

    You probably don’t need this function! If you’re gathering form data for submission, you probably want to go to data serialisation instead.