Skip to content

Input

An input is not a layout named useInputLayout, but it is still a fundamental FormField shape.

The relevant API is createInput(...).

Signature

ts
ts
import { createInput } from "@duplojs/form/vue";

const useMyInput = createInput(component, defaultParams);

Then:

ts
ts
const field = useMyInput(params);

Parameters of createInput(...)

ts
ts
createInput(component, {
	defaultValue,
	props?,
	template?,
});
  • component: Vue component compatible with the input contract.
  • defaultValue: default value of the field. Required.
  • props: default props injected into the component.
  • template: default input template.

Parameters of useMyInput(...)

ts
ts
useMyInput({
	label?,
	defaultValue?,
	props?,
	dataParser?,
	class?,
	template?,
});
  • label: label forwarded to the template.
  • defaultValue: local override of the initial value.
  • props: local props passed to the component.
  • dataParser: validation and transformation applied after the component.
  • class: CSS class added to the template.
  • template: local override of the input template.

Vue input component contract

The component must:

  • accept modelValue;
  • emit update:modelValue;
  • accept an id injected by the library.

It can also expose:

ts
ts
{
	check?(): Either;
	reset?(): void;
	dispose?(): void;
}

input template contract

Props

ts
ts
{
	getLabel?(): string;
	getCurrentValue(): unknown;
	getErrorMessage?(): string | null;
	fieldKey: string;
}

Slots

ts
ts
{
	input(): any;
}

Small template example

vue
vue
<script setup lang="ts">
import { type InputTemplateProperties } from "@duplojs/form/vue";

defineProps<InputTemplateProperties["props"]>();
defineSlots<InputTemplateProperties["slots"]>();
</script>

<template>
	<div>
		<label v-if="getLabel">
			{{ getLabel() }}
		</label>

		<slot name="input" />

		<small v-if="getErrorMessage">
			{{ getErrorMessage() }}
		</small>
	</div>
</template>
ts
ts
import { createTemplate } from "@duplojs/form/vue";
import MyInputTemplate from "./inputTemplate.vue";

export const useMyInputTemplate = createTemplate(
	"input",
	MyInputTemplate,
);

Minimal example

ts
ts
import { createInput } from "@duplojs/form/vue";
import BasicTextInput from "./BasicTextInput.vue";

export const useBasicTextInput = createInput(
	BasicTextInput,
	{
		defaultValue: "",
	},
);

Example with local validation

vue
vue
<script setup lang="ts">
import * as EE from "@duplojs/utils/either";
import { type ExposeInputProperties } from "@duplojs/form/vue";
import { ref } from "vue";

export interface Props {
	id: string;
	label: string;
	required?: boolean;
	errorMessage?: string;
}

const props = withDefaults(
	defineProps<Props>(),
	{
		required: false,
		errorMessage: "You must accept this condition.",
	},
);

const model = defineModel<boolean>({ default: false });
const currentError = ref<string | null>(null);

defineExpose<ExposeInputProperties>({
	check: () => {
		if (!props.required || model.value) {
			currentError.value = null;
			return EE.success(model.value);
		}

		currentError.value = props.errorMessage;
		return EE.error([{ key: props.id }]);
	},
	reset: () => {
		currentError.value = null;
	},
});
</script>

<template>
	<div>
		<label>
			<input
				v-model="model"
				type="checkbox"
				:id="props.id"
			/>
			{{ props.label }}
		</label>

		<small v-if="currentError">
			{{ currentError }}
		</small>
	</div>
</template>

What to remember

  • an input is already a FormField;
  • createInput(...) builds a field factory;
  • validation can happen in the component, in dataParser, or in both.

Released under the MIT License.