Что такое нативный компонентный подход
Нативный компонентный подход (Native Component Approach) - это использование встроенных HTML элементов и Web Components стандарта вместо разработки собственных компонентов с нуля. Это принцип, который говорит: "используй то, что уже есть в браузере, прежде чем создавать своё".
Суть подхода
Вместо того чтобы создавать свои компоненты для всего, начни с нативных HTML элементов:
<div class="my-button" onclick="handleClick()">
Нажми меня
</div>
<button onclick="handleClick()">
Нажми меня
</button>
Нативные HTML элементы
Для форм:
<div class="input-field" contenteditable>
Введи текст
</div>
<input type="text" placeholder="Введи текст">
<input type="email" placeholder="email@example.com">
<input type="password" placeholder="Пароль">
<input type="number" min="1" max="100">
<input type="date">
<textarea>Большой текст</textarea>
<select>
<option>Вариант 1</option>
<option>Вариант 2</option>
</select>
<button type="submit">Отправить</button>
Для структуры:
<header>Шапка сайта</header>
<nav>Навигация</nav>
<main>Основной контент</main>
<article>Статья</article>
<section>Секция</section>
<aside>Боковая колонка</aside>
<footer>Подвал</footer>
Для медиа:
<video controls>
<source src="video.mp4" type="video/mp4">
Ваш браузер не поддерживает видео
</video>
<audio controls>
<source src="audio.mp3" type="audio/mpeg">
</audio>
<picture>
<source media="(min-width: 800px)" srcset="large.jpg">
<img src="small.jpg" alt="Описание">
</picture>
Web Components
Web Components - стандарт W3C для создания переиспользуемых компонентов:
class MyButton extends HTMLElement {
connectedCallback() {
this.innerHTML = `
<button>${this.getAttribute('label') || 'Click me'}</button>
`;
this.querySelector('button').addEventListener('click', () => {
this.dispatchEvent(new CustomEvent('click-event'));
});
}
}
customElements.define('my-button', MyButton);
Использование:
<my-button label="Нажми"></my-button>
<script>
document.querySelector('my-button')
.addEventListener('click-event', () => console.log('Clicked!'));
</script>
Преимущества нативного подхода
1. Доступность (a11y) из коробки
<button>Отправить</button>
<div onclick="send()">Отправить</div>
2. Встроенное поведение
<form onsubmit="handleSubmit(e)">
<input type="text">
<button type="submit">Отправить</button>
</form>
<button>First</button>
<input type="text">
<button>Last</button>
3. SEO оптимизация
<article>
<h1>Заголовок статьи</h1>
<p>Контент</p>
</article>
<nav>Важно для навигации сайта</nav>
4. Производительность
Нативные элементы оптимизированы браузером:
- Быстрее рендерятся
- Меньше JavaScript кода
- Лучше работают на мобильных
Нативный подход в React
function Input({ value, onChange }) {
return (
<div className="custom-input">
<div contentEditable onChange={onChange}>{value}</div>
</div>
);
}
function Input({ value, onChange }) {
return (
<input
type="text"
value={value}
onChange={onChange}
className="input-style"
/>
);
}
Нативная форма:
function LoginForm() {
const handleSubmit = (e) => {
e.preventDefault();
const formData = new FormData(e.target);
console.log({
email: formData.get('email'),
password: formData.get('password')
});
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
name="email"
required
placeholder="Email"
/>
<input
type="password"
name="password"
required
placeholder="Пароль"
/>
<button type="submit">Войти</button>
</form>
);
}
Частые ошибки
Ошибка 1: Игнорирование семантики
<div onclick="alert('clicked')" class="button-style">
Кнопка
</div>
<button onclick="alert('clicked')" class="button-style">
Кнопка
</button>
Ошибка 2: Не использовать type атрибуты
<input value="email@example.com">
<input value="secret123">
<input value="5">
<input type="email" placeholder="Email">
<input type="password" placeholder="Пароль">
<input type="number" placeholder="Число">
Ошибка 3: Не использовать label для input
<label>Email</label>
<input type="email">
<label for="email">Email</label>
<input id="email" type="email">
Когда создавать свой компонент
Свой компонент нужен, когда:
- Нативный элемент не подходит по функционалу
- Нужен специфичный дизайн или поведение
- Компонент используется в многих местах проекта
- Нужна сложная логика
Пример - кастомный select с фильтром:
function FilteredSelect({ options, onChange }) {
const [isOpen, setIsOpen] = useState(false);
const [search, setSearch] = useState('');
const filtered = options.filter(opt =>
opt.label.toLowerCase().includes(search.toLowerCase())
);
return (
<div className="filtered-select">
<input
type="text"
value={search}
onChange={(e) => setSearch(e.target.value)}
onFocus={() => setIsOpen(true)}
/>
{isOpen && (
<ul>
{filtered.map(opt => (
<li key={opt.value} onClick={() => onChange(opt.value)}>
{opt.label}
</li>
))}
</ul>
)}
</div>
);
}
Итог
- Начни с нативных элементов - они работают лучше, чем ты можешь написать
- Используй правильную семантику - это улучшает SEO и a11y
- Не переизобретай велосипед -
<button> лучше чем <div onclick>
- Создавай свои компоненты только когда нужны - это экономит время и повышает качество
- Web Components - стандартный способ создания переиспользуемых элементов