Week 5 · Component Thinking

UI KIT CATALOG

A small parts list of reusable interface elements — Button, Card, Badge, Input, Modal, and Toast — each built as a self-contained, prop-driven JS function instead of one-off, hand-wired markup. Every piece below is rendered live by calling its factory function with different arguments, and every panel has a "Copy usage" button with the exact call used.

Parts6 components
FormatVanilla JS, no framework
PatterncreateX(props) → DOM node
StatusInteractive demo below
BTN-100

Button

createButton({ text, variant, size, onClick, disabled, icon, loading }) — returns a single <button> element. A separate setButtonLoading(btn, isLoading) helper toggles a spinner on an existing button for async actions.

Live rendering
variant
size
state / icon / loading
PropTypeDefault
textstringrequired
variantprimary · secondary · ghost · dangerprimary
sizesm · md · lgmd
onClickfunction
disabledbooleanfalse
loadingbooleanfalse
CARD-200

Card

createCard({ title, description, tag, variant, footerButtons }) — footerButtons accepts an array of button prop-objects, so cards compose the Button factory internally.

Live rendering
PropTypeDefault
titlestringrequired
descriptionstring""
tagstring
variantdefault · outlined · elevateddefault
footerButtonsarray<ButtonProps>[]
BADGE-600

Badge

createBadge({ text, tone }) — a small status pill, useful for labeling card tags, list rows, or notification counts with a semantic color.

Live rendering
PropTypeDefault
textstringrequired
toneneutral · info · success · warning · dangerneutral
INPUT-500

Input Field

createInput({ label, type, placeholder, value, helper, error, onChange }) — a labeled text field with either helper text or a validation error state.

Live rendering
PropTypeDefault
labelstring""
typestring (input type)text
placeholderstring""
helperstring
errorstring (overrides helper)
onChangefunction(value)
MODAL-300

Modal

createModal({ title, body, actions }) returns { open(), close() }. Modals stack — opening one from inside another layers it on top with its own backdrop, and Escape or a backdrop click closes only the topmost.

Live rendering
PropTypeDefault
titlestringrequired
bodystring / HTML""
actionsarray<ButtonProps>[Close]
.open() / .close()methods
TOAST-400

Toast Notification

showToast({ message, type, duration }) pushes onto a fixed corner stack. Each toast auto-dismisses on its own timer (shown by the shrinking bar) and can also be dismissed early — firing several keeps them stacked independently.

Live rendering
PropTypeDefault
messagestringrequired
typeinfo · success · warning · dangerinfo
durationms (0 = sticky)4000

Build notes — thinking in components

Earlier tasks started from a page and I wrote markup and logic wherever they were needed, so the same button or card ended up re-typed with small inconsistencies each time. Building this kit forced me to start from the element instead: decide what varies (text, variant, size) versus what stays fixed, and write one function that returns a DOM node for any combination of those props. That made the demo page itself much thinner — it's mostly just calls to createButton/createCard/createModal/showToast with different arguments, not hand-written HTML. It also pushed state and behavior (open/close, auto-dismiss timers, stacking order) inside each component's own function instead of scattering them across page-level event listeners, which helped me understand the separation between reusable component logic and the page that uses it — one of the core ideas behind React.