Skip to content

Rule Creation ​

Use and extend any built-in rule or define your own β€” asynchronous rules, cross-field rules, or even required-type rules that determine whether a field must be filled.

πŸ“ Defining Rules ​

The defineRule() API requires a name string that is used to delcare the rules within the field. It also requires a validate() function that holds the validation logic. When not using a locale source, a default message must be supplied via message.

js
defineRule('minlength', {
  validate: (value, [limit]) => {
    return value.length >= limit
  },
  message: 'The {field} must be at least {limit} characters long.'
})

πŸ“ Declaring Rules ​

Delcare the rule name as HTML attributes, then use it to write your own logic. The validate() function gives you access to the field’s value, params, and context.

html
<form>
  <input type="text" name="username" value="jim" />
  <input type="text" name="age" between="18,50" value="25" />
</form>

The validate() function for between accepts:

  • value β†’ 25
  • params β†’ [18,50]
  • context:
json
{
  "field": "username",
  "type": "text",
  "attrValue": "18,50",
  "form": {
    "username": "jim",
    "age": "25"
  }
}

⚑ Built-in Rules ​

The Rules offers 50+ built-in validation rules β€” including files, dates, multi-selects, conditional requirements, and full support for all native browser rules. Import each rule individually, import by group, or import all at once (not recommended).

js
import { defineRule } from 'suriform'
import { min, max } from 'suriform/rules'

defineRule('min', min)
defineRule('max', max)

Each built-in rule are designed to be extended using object spreading. Override the message, change the format, or extend the validator however you want.

js
import { defineRule } from 'suriform'
import { min } from 'suriform/rules'

defineRule('min', {
  ...min,
  message: 'Value must be greater than or equal to {min}.'
})

πŸ”„ Asynchronous ​

Return a simple boolean result to trigger the rule’s default message or chain multiple conditions with nested messages to have a more dynamic messaging.

js
defineRule('username', {
  validate: async (value) => {
    const res = await fetch(`/api/check-username?u=${value}`)
    const data = await res.json()
    return data.available
  },
  message: 'The {field} is already taken.'
})

πŸ’‘ Learn more about message resolving with the Messaging guide.

↔️ Cross-Field ​

Using the checksTarget flag, the validate() function will have access to the FormData within the context object. This allows for easy access to the target field’s value.

js
defineRule('match', {
  validate: (value, [target], { form }) => {
    return value == form[target]
  },
  checksTarget: true,
  message: 'Fields do not match.'
})
html
<form>
  <input type="text" name="foo" match="bar" />
  <input type="text" name="bar" />
</form>

πŸ’‘ Combine cross-field logic with async rules for complex validation scenarios.

βœ… Required-Type ​

With the checksRequired flag, the system registers the rule in a different registry that runs an additional isFieldRequired() check, dedicated to required-type rules.

js
defineRule('required-with', {
  validate: (_, [target], { form }) => {
    if (!target) return false
    return !!form[target]
  },
  checksTarget: true,
  checksRequired: true
})
html
<form>
  <input type="text" name="foo" required-with="bar" />
  <input type="text" name="bar" />
</form>

πŸ’‘ Learn more about validation flow with the validateForm() API.

Released under the MIT License.