New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

lite-form

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

lite-form

Form HOC for Web Components. It's also works for LitElement.

latest
Source
npmnpm
Version
1.1.1
Version published
Maintainers
1
Created
Source

Lite Form

Form HOC for Web Components. It's also works for LitElement.

Examples

Lite Form implements a Formik-like API, so just try using it. See API Reference for more information.

Native Inputs

import { LitElement, html } from 'lit-element'
import { withForm } from 'lite-form'

class MyForm extends LitElement {
  static get properties() {
    return {
      values: { type: Object },
      errors: { type: Object },
      touched: { type: Object }
    }
  }

  render() {
    return html`
      <form method="POST" @submit=${this.handleSubmit}>
        <input
          id="login"
          @input=${this.handleChange}
          @change=${this.handleChange}
          @blur=${this.handleBlur}
          .value=${this.values.login}
        />
        ${this.errors.login && this.touched.login
          ? this.errors.login
          : ''}
        <input
          id="password"
          type="password"
          @input=${this.handleChange}
          @change=${this.handleChange}
          @blur=${this.handleBlur}
          .value=${this.values.password}
        />

        ${this.errors.password && this.touched.password
          ? this.errors.password
          : ''}

        <button type="submit">Submit</button>
      </form>
    `
  }
}

const enhance = withForm({
  initialValues: { login: '', password: '' },
  onSubmit: values => console.log(values),
  validationSchema: {
    login: value => {
      if (!value) return 'Required'
    },
    password: value => {
      if (value.length < 5) return 'Must be more than 5 letters'
    }
  }
})

customElements.define('native-inputs-form', enhance(MyForm))

Custom Inputs

It will become more concise if you create your own <custom-input> using withField and <error-message> using withError:

import { LitElement, html } from 'lit-element'
import { withForm } from 'lite-form'

class MyForm extends LitElement {
  render() {
    return html`
      <form method="POST" @submit=${this.handleSubmit}>
        <custom-input name="login"></custom-input>
        <error-message name="login"></error-message>

        <custom-input name="password" type="password"></custom-input>
        <error-message name="password"></error-message>

        <button type="submit">Submit</button>
      </form>
    `
  }
}

const enhance = withForm({
  initialValues: { login: '', password: '' },
  onSubmit: values => console.log(values),
  validationSchema: {
    login: value => {
      if (!value) return 'Required'
    },
    password: value => {
      if (value.length < 5) return 'Must be more than 5 letters'
    }
  }
})

customElements.define('wrapped-inputs-form', enhance(MyForm))

Here are the components:

// custom-input
import { LitElement, html } from 'lit-element'
import { withField } from 'lite-form'

export default class ExwcInput extends LitElement {
  static get properties() {
    return {
      type: { type: String },
      name: { type: String },
      value: { type: String }
    }
  }

  constructor() {
    super()
    this.type = 'text'
    this.value = ''
  }

  render() {
    return html`
      <input
        autocomplete="off"
        type=${this.type}
        name=${this.name}
        .value=${this.value}
        @input=${this.handleChange}
      />
    `
  }
}

customElements.define('custom-input', withField(ExwcInput))
// error-message
import { LitElement, html } from 'lit-element'
import { withError } from 'lite-form'

export default class ExwcInput extends LitElement {
  static get properties() {
    return {
      name: { type: String },
      error: { type: String },
      touched: { type: Boolean }
    }
  }

  render() {
    return html`
      ${this.error && this.touched
        ? this.error
        : ''}
    `
  }
}

customElements.define('error-message', withError(ExwcInput))

Form Base Class

You can also create your own base form class. For example:

// Form Base Class
import { LitElement, html } from 'lit-element'
import { withForm } from 'lite-form'

class LiteForm extends LitElement {
  render() {
    return html`<form @submit=${this.handleSubmit} method=${this.method}>
      ${this.formRender(this)}
    </form>`
  }
}

customElements.define('lite-form', withForm(LiteForm))

And use it in HTML:

// Using Base Form Class
import { html, render } from 'lit-html'


const formRender = ({ values, handleBlur, handleChange }) =>
  html` 
    <custom-input name="login"></custom-input>
    <error-message name="login"></error-message>

    <custom-input name="password" type="password"></custom-input>
    <error-message name="password"></error-message>

    <button type="submit">Submit</button>
  `

const MyForm = html`
  <lite-form
    method="post"
    .formRender=${formRender}
    .onSubmit=${values => console.log(values)}
    .initialValues=${{
      login: '',
      password: ''
    }}
    .validationSchema=${{
      login: value => {
        if (!value) return 'Required'
      },
      password: value => {
        if (value.length < 5) return 'Must be more than 5 letters'
      }
    }}
  ></lite-form>
`

render(html`${MyForm}`, document.getElementById('root'))

Don't use a slot instead of providing a form template if you need from events - the form will not trigger its events on elements inside the slot.

Builtin Element Extends

You can also extends builtin form element using Lite Form:

import { withForm } from 'lite-form'

class LiteForm extends HTMLFormElement {
  connectedCallback() {
    this.addEventListener('submit', this.handleSubmit)
    this.addEventListener('reset', this.handleReset)
  }

  disconnectedCallback() {
    this.removeEventListener('submit', this.handleSubmit)
    this.removeEventListener('reset', this.handleReset)
  }
}

customElements.define('native-form', withForm(LiteForm), { extends: 'form' })

And use it in HTML:

// Using form element
import { html } from 'lit-element'

const MyForm = html`
  <form
    is="native-form"
    .onSubmit=${values => console.log(values)}
    .initialValues=${{
      login: '',
      password: ''
    }}
    .validationSchema=${{
      login: value => {
        if (!value) return 'Required'
      },
      password: value => {
        if (value.length < 5) return 'Must be more than 5 letters'
      }
    }}
  >
    <custom-input name="login"></custom-input>
    <error-message name="login"></error-message>

    <custom-input name="password" type="password"></custom-input>
    <error-message name="password"></error-message>

    <button type="submit">Submit</button>
  </form>
`

render(html`${MyForm}`, document.getElementById('root'))

Customising builtin elements does not work in Safari and iOS (13) without polyfill.

API Reference

withForm

Usage

withForm(config)(Component) or withForm(ComponentWithConfig)

Instead of using config in the HOC, you can put it in the Component class. This will allow you to create your own base form class.

Config
  • onSubmit: (values, props)=>{}
  • initialValues: { propName: value } || props => ({ propName: value })
  • validationSchema: { propName: (value, props) => 'error'||{} }
  • validateOnBlur: boolean. Default: true
  • validateOnChang: boolean. Default: true
Props
  • values: object
  • errors: object
  • touched: object
  • isValid: boolean
  • handleSubmit: function
  • handleChange: (path || event, value) => {}. event: Event: {target: {name || id, value}} || CustomEvent: {detail: {name || id, value}}
  • handleBlur: (path || event) => {}. event: Event: {target: {name || id}} || CustomEvent: {detail: {name || id}}
  • handleValidate: function
  • handleReset: function
Events
  • values_change: e=>console.log(e.detail.values)
  • errors_touched_change: e=>console.log(e.detail.errors, e.detail.touched)

withField

Usage

withField(Component) or withField(config)(Component)

Component must have name (means path) or id attribute.

Config (optional)
  • captureBlur boolean. Default: true
  • listenChange boolean. Default: false

captureBlur is usefull if you don't use Shadow DOM in your Component or if you use it with slots. If you use Shadow DOM without slots the event will be bubbling (composed) by default and you don't need to use capture for it.

listenChange is usefull if you don't using Shadow DOM in your Component or if your Component dispatch @change event (with options {bubbles: true, composed: true}) instead of using handleChange method. It is useless if you use Shadow DOM in your Component and not dispatch @change event, because js will replace event.target from your internal input to your Component, and it will lose target.value

Props
  • value: any
  • handleChange: (value || event) => {}. event: Event: {target: {value}} || CustomEvent: {detail: {value}}
  • handleBlur: function
Listening Events
  • blur: Event or CustomEvent. If captureBlur==true it will be listening on capturing phase.
  • change: Event: {target: {value}} || CustomEvent: {details: {value}}. Listening only if listenChange==true

withError

Usage

withError(Component)

Component must have name (means path) or id attribute.

Props
  • error: object
  • touched: object

withValue

Usage

withValue(Component)

Component must have name (means path) or id attribute.

Props
  • value: any

withFormClass

Usage

withFormClass(Component)

Props
  • _formClass: your withForm(Component) class. It's usefull to build your own HOCs.

Remarks

  • Don't use slots with input elements inside <form> tag if you need to catch form's events from them!
  • Don't use Shadow DOM if you need autofill to your form (e.g. login & password)!
  • Customising builtin elements does not work in Safari and iOS (13) without polyfill.

Keywords

form

FAQs

Package last updated on 20 Dec 2021

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts