Atomico — это современная библиотека для разработки веб-компонентов на JavaScript, которая использует реактивный подход, схожий с React, но ориентированная на нативные Custom Elements. Она идеально подходит для создания кастомных формовых элементов с полной поддержкой реактивности, состояния и событий.
Каждый компонент в Atomico создается с помощью функции
component. Она принимает функцию рендера и возвращает
объект, который можно использовать как стандартный Custom Element. Для
формы важно правильно определить свойства (props) и события
(events), чтобы компонент корректно взаимодействовал с
внешним кодом.
import { component, html, useState } from "atomico";
function CustomInput({ value, placeholder, onChange }) {
const [inputValue, setInputValue] = useState(value || "");
function handleInput(event) {
setInputValue(event.target.value);
onChange?.(event.target.value);
}
return html`
<input
type="text"
.value=${inputValue}
placeholder=${placeholder || ""}
@input=${handleInput}
/>
`;
}
CustomInput.props = {
value: String,
placeholder: String,
onChange: Function
};
export const customInput = component(CustomInput);
Ключевые моменты:
useState для управления локальным
состоянием.onChange через props для внешней
синхронизации.@event.Для сложных форм, включающих несколько полей и проверку данных, Atomico позволяет использовать реактивные объекты и хуки. Например, можно создать форму регистрации с валидаторами:
function RegistrationForm() {
const [formData, setFormData] = useState({ username: "", email: "" });
const [errors, setErrors] = useState({});
function handleChange(field) {
return (value) => {
setFormData({ ...formData, [field]: value });
};
}
function validate() {
const newErrors = {};
if (!formData.username) newErrors.username = "Username required";
if (!formData.email.includes("@")) newErrors.email = "Invalid email";
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
}
function handleSubmit(event) {
event.preventDefault();
if (validate()) {
console.log("Submitting", formData);
}
}
return html`
<form @submit=${handleSubmit}>
<label>
Username:
<custom-input
.value=${formData.username}
placeholder="Enter username"
.onCha nge=${handleChange("username")}
></custom-input>
${errors.username && html`<span class="error">${errors.username}</span>`}
</label>
<label>
Email:
<custom-input
.value=${formData.email}
placeholder="Enter email"
.onCha nge=${handleChange("email")}
></custom-input>
${errors.email && html`<span class="error">${errors.email}</span>`}
</label>
<button type="submit">Register</button>
</form>
`;
}
export const registrationForm = component(RegistrationForm);
Особенности:
formData для хранения
значений всех полей.validate.Atomico позволяет легко передавать события из кастомного элемента
наружу. Для этого можно использовать dispatchEvent внутри
компонента:
function CustomSelect({ options, value }) {
function handleChange(event) {
const selectedValue = event.target.value;
dispatchEvent(new CustomEvent("change", { detail: selectedValue }));
}
return html`
<select .value=${value} @change=${handleChange}>
${options.map(option => html`<option value=${option.value}>${option.label}</option>`)}
</select>
`;
}
CustomSelect.props = {
options: Array,
value: String
};
export const customSelect = component(CustomSelect);
dispatchEvent позволяет родительским компонентам
подписываться на событие change.CustomEvent.detail.Atomico поддерживает вложенные кастомные элементы и композицию без потери реактивности. Можно строить модульные формы, где каждый элемент управляет собственным состоянием и взаимодействует через props и события.
function UserForm() {
const [user, setUser] = useState({ role: "", name: "" });
return html`
<form>
<custom-input
.value=${user.name}
placeholder="Name"
.onCha nge=${val => setUser({ ...user, name: val })}
></custom-input>
<custom-select
.options=${[
{ value: "admin", label: "Admin" },
{ value: "user", label: "User" }
]}
.value=${user.role}
@change=${e => setUser({ ...user, role: e.detail })}
></custom-select>
</form>
`;
}
export const userForm = component(UserForm);
Atomico позволяет интегрировать CSS напрямую через шаблон
html или использовать Shadow DOM для изоляции стилей. Для
формовых элементов важно соблюдать доступность:
<label> для привязки к
полям.aria-* атрибутов.return html`
<label for="username">Username</label>
<input id="username" type="text" aria-describedby="username-error"/>
${errors.username && html`<span id="username-error" role="alert">${errors.username}</span>`}
`;
Кастомные элементы форм в Atomico строятся на следующих принципах:
useState,
useEffect).Это позволяет создавать полностью настраиваемые, расширяемые и поддерживаемые формы, которые интегрируются как в небольшие виджеты, так и в крупные веб-приложения.