mirror of
https://github.com/github/awesome-copilot.git
synced 2026-02-20 02:15:12 +00:00
Add skill to create web forms
Add skill to create web forms
This commit is contained in:
@@ -31,6 +31,7 @@ Skills differ from other primitives by supporting bundled assets (scripts, code
|
||||
| [azure-static-web-apps](../skills/azure-static-web-apps/SKILL.md) | Helps create, configure, and deploy Azure Static Web Apps using the SWA CLI. Use when deploying static sites to Azure, setting up SWA local development, configuring staticwebapp.config.json, adding Azure Functions APIs to SWA, or setting up GitHub Actions CI/CD for Static Web Apps. | None |
|
||||
| [chrome-devtools](../skills/chrome-devtools/SKILL.md) | Expert-level browser automation, debugging, and performance analysis using Chrome DevTools MCP. Use for interacting with web pages, capturing screenshots, analyzing network traffic, and profiling performance. | None |
|
||||
| [copilot-sdk](../skills/copilot-sdk/SKILL.md) | Build agentic applications with GitHub Copilot SDK. Use when embedding AI agents in apps, creating custom tools, implementing streaming responses, managing sessions, connecting to MCP servers, or creating custom agents. Triggers on Copilot SDK, GitHub SDK, agentic app, embed Copilot, programmable agent, MCP server, custom agent. | None |
|
||||
| [create-web-form](../skills/create-web-form/SKILL.md) | Create robust, accessible web forms with best practices for HTML structure, CSS styling, JavaScript interactivity, form validation, and server-side processing. Use when asked to "create a form", "build a web form", "add a contact form", "make a signup form", or when building any HTML form with data handling. Covers PHP and Python backends, MySQL database integration, REST APIs, XML data exchange, accessibility (ARIA), and progressive web apps. | `references/accessibility.md`<br />`references/aria-form-role.md`<br />`references/css-styling.md`<br />`references/form-basics.md`<br />`references/form-controls.md`<br />`references/form-data-handling.md`<br />`references/html-form-elements.md`<br />`references/html-form-example.md`<br />`references/hypertext-transfer-protocol.md`<br />`references/javascript.md`<br />`references/php-cookies.md`<br />`references/php-forms.md`<br />`references/php-json.md`<br />`references/php-mysql-database.md`<br />`references/progressive-web-app.md`<br />`references/python-as-web-framework.md`<br />`references/python-contact-form.md`<br />`references/python-flask-app.md`<br />`references/python-flask.md`<br />`references/security.md`<br />`references/styling-web-forms.md`<br />`references/web-api.md`<br />`references/web-performance.md`<br />`references/xml.md` |
|
||||
| [excalidraw-diagram-generator](../skills/excalidraw-diagram-generator/SKILL.md) | Generate Excalidraw diagrams from natural language descriptions. Use when asked to "create a diagram", "make a flowchart", "visualize a process", "draw a system architecture", "create a mind map", or "generate an Excalidraw file". Supports flowcharts, relationship diagrams, mind maps, and system architecture diagrams. Outputs .excalidraw JSON files that can be opened directly in Excalidraw. | `references/element-types.md`<br />`references/excalidraw-schema.md`<br />`scripts/.gitignore`<br />`scripts/README.md`<br />`scripts/add-arrow.py`<br />`scripts/add-icon-to-diagram.py`<br />`scripts/split-excalidraw-library.py`<br />`templates/business-flow-swimlane-template.excalidraw`<br />`templates/class-diagram-template.excalidraw`<br />`templates/data-flow-diagram-template.excalidraw`<br />`templates/er-diagram-template.excalidraw`<br />`templates/flowchart-template.excalidraw`<br />`templates/mindmap-template.excalidraw`<br />`templates/relationship-template.excalidraw`<br />`templates/sequence-diagram-template.excalidraw` |
|
||||
| [gh-cli](../skills/gh-cli/SKILL.md) | GitHub CLI (gh) comprehensive reference for repositories, issues, pull requests, Actions, projects, releases, gists, codespaces, organizations, extensions, and all GitHub operations from the command line. | None |
|
||||
| [git-commit](../skills/git-commit/SKILL.md) | Execute git commit with conventional commit message analysis, intelligent staging, and message generation. Use when user asks to commit changes, create a git commit, or mentions "/commit". Supports: (1) Auto-detecting type and scope from changes, (2) Generating conventional commit messages from diff, (3) Interactive commit with optional type/scope/description overrides, (4) Intelligent file staging for logical grouping | None |
|
||||
|
||||
87
skills/create-web-form/SKILL.md
Normal file
87
skills/create-web-form/SKILL.md
Normal file
@@ -0,0 +1,87 @@
|
||||
---
|
||||
name: create-web-form
|
||||
description: 'Create robust, accessible web forms with best practices for HTML structure, CSS styling, JavaScript interactivity, form validation, and server-side processing. Use when asked to "create a form", "build a web form", "add a contact form", "make a signup form", or when building any HTML form with data handling. Covers PHP and Python backends, MySQL database integration, REST APIs, XML data exchange, accessibility (ARIA), and progressive web apps.'
|
||||
---
|
||||
|
||||
# Create Web Form Skill
|
||||
|
||||
## Overview
|
||||
|
||||
This skill provides comprehensive reference materials and best practices for creating web forms. It covers HTML syntax, UI/UX design, form validation, server-side processing (PHP and Python), data handling, and network communication.
|
||||
|
||||
## Purpose
|
||||
|
||||
Enable developers to build robust, accessible, and user-friendly web forms by providing:
|
||||
|
||||
- HTML form syntax and structure
|
||||
- CSS styling techniques for form elements
|
||||
- JavaScript for form interactivity and validation
|
||||
- Accessibility best practices
|
||||
- Server-side form processing with PHP and Python
|
||||
- Database integration methods
|
||||
- Network data handling and security
|
||||
- Performance optimization
|
||||
|
||||
## Reference Files
|
||||
|
||||
This skill includes the following reference documentation:
|
||||
|
||||
### UI & Styling
|
||||
- `styling-web-forms.md` - Form styling techniques and best practices
|
||||
- `css-styling.md` - Comprehensive CSS reference for form styling
|
||||
|
||||
### User Experience
|
||||
- `accessibility.md` - Web accessibility guidelines for forms
|
||||
- `javascript.md` - JavaScript techniques for form functionality
|
||||
- `form-controls.md` - Native form controls and their usage
|
||||
- `progressive-web-app.md` - Progressive web app integration
|
||||
|
||||
### HTML Structure
|
||||
- `form-basics.md` - Fundamental HTML form structure
|
||||
- `aria-form-role.md` - ARIA roles for accessible forms
|
||||
- `html-form-elements.md` - Complete HTML form elements reference
|
||||
- `html-form-example.md` - Practical HTML form examples
|
||||
- `html-reference.md` - General HTML reference
|
||||
|
||||
### Server-Side Processing
|
||||
- `form-data-handling.md` - Network form data handling
|
||||
- `php-forms.md` - PHP form processing
|
||||
- `php-cookies.md` - Cookie management in PHP
|
||||
- `php-json.md` - JSON handling in PHP
|
||||
- `php-mysql-database.md` - Database integration with PHP
|
||||
- `php-reference.md` - PHP language reference
|
||||
- `python-contact-form.md` - Python contact form implementation
|
||||
- `python-flask.md` - Flask forms tutorial
|
||||
- `python-flask-app.md` - Building Flask web applications
|
||||
- `python-as-web-framework.md` - Python web framework basics
|
||||
|
||||
### Data & Network
|
||||
- `xml.md` - XML data format reference
|
||||
- `hypertext-transfer-protocol.md` - HTTP protocol reference
|
||||
- `security.md` - Web security best practices
|
||||
- `web-api.md` - Web API integration
|
||||
- `web-performance.md` - Performance optimization techniques
|
||||
|
||||
## Usage
|
||||
|
||||
When creating a web form, consult the appropriate reference files based on your needs:
|
||||
|
||||
1. **Planning**: Review `form-basics.md` and `form-controls.md`
|
||||
2. **Structure**: Use `html-form-elements.md` and `aria-form-role.md`
|
||||
3. **Styling**: Reference `styling-web-forms.md` and `css-styling.md`
|
||||
4. **Interactivity**: Apply techniques from `javascript.md`
|
||||
5. **Accessibility**: Follow guidelines in `accessibility.md`
|
||||
6. **Server Processing**: Choose between PHP or Python references
|
||||
7. **Data Storage**: Consult database and data format references
|
||||
8. **Optimization**: Review `web-performance.md` and `security.md`
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Always validate input on both client and server sides
|
||||
- Ensure forms are accessible to all users
|
||||
- Use semantic HTML elements
|
||||
- Implement proper error handling and user feedback
|
||||
- Secure form data transmission with HTTPS
|
||||
- Follow progressive enhancement principles
|
||||
- Test forms across different browsers and devices
|
||||
- Optimize for performance and user experience
|
||||
512
skills/create-web-form/references/accessibility.md
Normal file
512
skills/create-web-form/references/accessibility.md
Normal file
@@ -0,0 +1,512 @@
|
||||
# Web Accessibility Reference
|
||||
|
||||
A consolidated reference guide drawn from MDN Web Docs covering core accessibility
|
||||
concepts, authoring guidelines, safe browsing practices, ARIA-based widgets, and
|
||||
mobile accessibility requirements.
|
||||
|
||||
---
|
||||
|
||||
## 1. Accessibility Overview
|
||||
|
||||
> **Source:** https://developer.mozilla.org/en-US/docs/Web/Accessibility
|
||||
|
||||
### What Is Accessibility?
|
||||
|
||||
**Accessibility** (abbreviated as **A11y** -- "a" + 11 characters + "y") in web
|
||||
development means enabling as many people as possible to use websites, even when
|
||||
those people's abilities are limited in some way.
|
||||
|
||||
> "The Web is fundamentally designed to work for all people, whatever their
|
||||
> hardware, software, language, location, or ability. When the Web meets this
|
||||
> goal, it is accessible to people with a diverse range of hearing, movement,
|
||||
> sight, and cognitive ability." -- W3C
|
||||
|
||||
Key points:
|
||||
|
||||
- Technology makes things **easier** for many people.
|
||||
- Technology makes things **possible** for people with disabilities.
|
||||
- Accessibility spans physical, cognitive, hearing, movement, and sight abilities.
|
||||
|
||||
### Core Principles
|
||||
|
||||
1. **Semantic HTML** -- Use correct elements for their intended purpose.
|
||||
2. **Keyboard Navigation** -- Ensure full functionality without a mouse.
|
||||
3. **Assistive Technology Support** -- Maintain compatibility with screen readers
|
||||
and other tools.
|
||||
4. **Perceivability** -- Content must be perceivable through multiple senses.
|
||||
5. **Operability** -- All functionality must be keyboard accessible.
|
||||
6. **Understandability** -- Clear language and predictable behavior.
|
||||
7. **Robustness** -- Works across diverse assistive technologies.
|
||||
|
||||
### Beginner Tutorial Modules (MDN Learn Web Development)
|
||||
|
||||
| Module | Description |
|
||||
|--------|-------------|
|
||||
| What is Accessibility? | Groups to consider, tools users rely on, workflow integration |
|
||||
| Accessibility Tooling and Assistive Technology | Tools for solving accessibility issues |
|
||||
| HTML: A Good Basis for Accessibility | Semantic markup and correct element usage |
|
||||
| CSS and JavaScript Best Practices | Accessible implementation of CSS and JS |
|
||||
| WAI-ARIA Basics | Adding semantics for complex UI controls and dynamic content |
|
||||
| Accessible Multimedia | Text alternatives for video, audio, and images |
|
||||
| Mobile Accessibility | iOS/Android tools and mobile-specific considerations |
|
||||
|
||||
### Key Standards and Frameworks
|
||||
|
||||
- **WCAG (Web Content Accessibility Guidelines)** -- organized into Perceivable,
|
||||
Operable, Understandable, and Robust categories.
|
||||
- **ARIA (Accessible Rich Internet Applications)** -- 53+ attributes and 87+
|
||||
roles for adding semantic meaning to custom widgets.
|
||||
|
||||
---
|
||||
|
||||
## 2. Information for Web Authors
|
||||
|
||||
> **Source:** https://developer.mozilla.org/en-US/docs/Web/Accessibility/Guides/Information_for_Web_authors
|
||||
|
||||
### Guidelines and Regulations
|
||||
|
||||
#### ARIA Authoring Practices Guide (APG)
|
||||
|
||||
- **Provider:** W3C
|
||||
- **URL:** https://www.w3.org/WAI/ARIA/apg/
|
||||
- Design patterns and functional examples for accessible web experiences.
|
||||
- Covers how to apply accessibility semantics to common design patterns and
|
||||
widgets.
|
||||
|
||||
#### Web Content Accessibility Guidelines (WCAG)
|
||||
|
||||
- **Provider:** W3C Web Accessibility Initiative (WAI)
|
||||
- **URL:** https://www.w3.org/WAI/standards-guidelines/wcag/
|
||||
- Important baseline guidelines being adopted by EU accessibility regulations.
|
||||
|
||||
#### ARIA on MDN
|
||||
|
||||
- Complete guides to ARIA roles, properties, and attributes.
|
||||
- Best practices and code examples for each role.
|
||||
|
||||
### How-to Guides
|
||||
|
||||
| Guide | Provider | URL |
|
||||
|-------|----------|-----|
|
||||
| Accessibility for Teams | U.S. General Services Administration | https://digital.gov/guides/accessibility-for-teams/ |
|
||||
| Accessible Web Page Authoring | IBM | https://www.ibm.com/able/requirements/requirements/ |
|
||||
|
||||
### Automated Checking and Repair Tools
|
||||
|
||||
#### Browser Extensions
|
||||
|
||||
| Tool | URL |
|
||||
|------|-----|
|
||||
| HTML CodeSniffer | https://squizlabs.github.io/HTML_CodeSniffer/ |
|
||||
| aXe DevTools | Built into browser DevTools |
|
||||
| Lighthouse Accessibility Audit | Chrome DevTools integrated |
|
||||
| Accessibility Insights | https://accessibilityinsights.io/ |
|
||||
| WAVE | https://wave.webaim.org/extension/ |
|
||||
|
||||
#### Build-Process / Programmatic Testing
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| axe-core | Accessibility engine for automated testing (dequelabs/axe-core) |
|
||||
| eslint-plugin-jsx-a11y | ESLint plugin for JSX accessibility rules |
|
||||
| Lighthouse Audits | Programmable audit runner (GoogleChrome/lighthouse) |
|
||||
| AccessLint.js | Automated a11y linting library |
|
||||
|
||||
#### Continuous Integration
|
||||
|
||||
- **AccessLint** (https://accesslint.com/) -- integrates with GitHub pull
|
||||
requests for automated accessibility review.
|
||||
|
||||
### Testing Recommendations
|
||||
|
||||
Simulation and testing methods to employ:
|
||||
|
||||
- Color blindness simulation
|
||||
- Low vision simulation
|
||||
- Low contrast testing
|
||||
- Zoom testing
|
||||
- Keyboard-only navigation (disable the mouse)
|
||||
- Touch-only testing
|
||||
- Voice command testing
|
||||
- Testing with a **Web Disability Simulator** browser extension
|
||||
|
||||
Best practice: **Test with real users whenever possible.**
|
||||
|
||||
---
|
||||
|
||||
## 3. Browsing Safely
|
||||
|
||||
> **Source:** https://developer.mozilla.org/en-US/docs/Web/Accessibility/Guides/Browsing_safely
|
||||
|
||||
### Conditions Addressed
|
||||
|
||||
| Condition | Common Triggers |
|
||||
|-----------|-----------------|
|
||||
| Vestibular Disorders | Motion, animations, parallax effects |
|
||||
| Seizure Disorders | Flashing (3+ per second), flickering, high-contrast color changes |
|
||||
| Photosensitivity | Color intensity, flashing, high contrast |
|
||||
| Traumatic Brain Injury (TBI) | High cognitive load from color processing |
|
||||
|
||||
### CSS Media Feature: `prefers-reduced-motion`
|
||||
|
||||
Detects the user's OS-level preference for reduced motion.
|
||||
|
||||
```css
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
* {
|
||||
animation: none !important;
|
||||
transition: none !important;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
CSS transition events that developers can listen to:
|
||||
|
||||
- `transitionrun`
|
||||
- `transitionstart`
|
||||
- `transitionend`
|
||||
- `transitioncancel`
|
||||
|
||||
### Platform-Level Browser Controls
|
||||
|
||||
| Platform | Setting | Notes |
|
||||
|----------|---------|-------|
|
||||
| Safari Desktop (10.1+) | Disable Auto-Play | Does not affect animated GIFs |
|
||||
| iOS Safari (10.3+) | Reduce Motion (OS Accessibility settings) | GIFs unaffected |
|
||||
| Firefox | `image.animation_mode` set to `"none"` | Disables all animated GIFs |
|
||||
| Reader Mode (various) | Content Blockers, text-to-speech, font/zoom | Reduces distractions |
|
||||
|
||||
### Useful Browser Extensions
|
||||
|
||||
| Extension | Purpose | Browser |
|
||||
|-----------|---------|---------|
|
||||
| Gif Blocker | Blocks all GIFs | Chrome |
|
||||
| Gif Scrubber | Pause/play/scrub GIFs like a video | Chrome |
|
||||
| Beeline Reader | Grayscale mode, dyslexia-friendly fonts, contrast | Chrome, Edge, Firefox |
|
||||
|
||||
### Operating System Accessibility Features
|
||||
|
||||
**Windows 10:**
|
||||
|
||||
- Settings > Ease of Access > Display -- Turn off animations.
|
||||
- Settings > Ease of Access > Display > Color Filters -- Toggle grayscale.
|
||||
- Grayscale reduces cognitive load for TBI, photosensitive epilepsy, and other
|
||||
conditions.
|
||||
|
||||
**macOS:**
|
||||
|
||||
- System Preferences > Accessibility > Display -- "Reduce motion" option.
|
||||
|
||||
### WCAG Compliance: Success Criterion 2.3.1
|
||||
|
||||
**Three Flashes or Below Threshold** -- content must not flash more than three
|
||||
times per second unless the flash is below the general flash and red flash
|
||||
thresholds.
|
||||
|
||||
### Best Practices for Developers
|
||||
|
||||
**Do:**
|
||||
|
||||
- Support the `prefers-reduced-motion` media query.
|
||||
- Keep flashing below 3 times per second.
|
||||
- Provide play/pause controls for all animations.
|
||||
- Test with OS accessibility features enabled.
|
||||
|
||||
**Do not:**
|
||||
|
||||
- Auto-play videos or animations without user controls.
|
||||
- Use high-frequency flashing or strobing effects.
|
||||
- Assume all users can tolerate motion.
|
||||
|
||||
### Implementation Checklist
|
||||
|
||||
- [ ] Add `@media (prefers-reduced-motion: reduce)` rules to CSS.
|
||||
- [ ] Disable auto-play animations when the user preference is set.
|
||||
- [ ] Ensure GIFs have pause controls.
|
||||
- [ ] Test in Windows and macOS accessibility modes.
|
||||
- [ ] Validate against WCAG 2.3.1 (Three Flashes criterion).
|
||||
|
||||
---
|
||||
|
||||
## 4. Accessible Web Applications and Widgets
|
||||
|
||||
> **Source:** https://developer.mozilla.org/en-US/docs/Web/Accessibility/Guides/Accessible_web_applications_and_widgets
|
||||
|
||||
### The Problem
|
||||
|
||||
Custom JavaScript widgets (sliders, menu bars, tabs, dialogs) built with generic
|
||||
HTML elements like `<div>` and `<span>` lack semantic meaning for assistive
|
||||
technologies. Dynamic content changes may not be detected by screen readers.
|
||||
|
||||
### ARIA (Accessible Rich Internet Applications)
|
||||
|
||||
ARIA fills the gap between standard HTML and desktop-style UI controls with three
|
||||
types of attributes:
|
||||
|
||||
1. **Roles** -- Describe widgets not natively available in HTML (sliders, menu
|
||||
bars, tabs, dialogs).
|
||||
2. **Properties** -- Describe characteristics (draggable, required, has popup).
|
||||
3. **States** -- Describe current interaction state (busy, disabled, selected,
|
||||
hidden).
|
||||
|
||||
**Important:** Prefer semantic HTML elements over ARIA when available. ARIA is a
|
||||
progressive enhancement for dynamic components.
|
||||
|
||||
### Example: Tabs Widget
|
||||
|
||||
**Without ARIA (non-accessible):**
|
||||
|
||||
```html
|
||||
<ol>
|
||||
<li id="ch1Tab">
|
||||
<a href="#ch1Panel">Chapter 1</a>
|
||||
</li>
|
||||
<li id="ch2Tab">
|
||||
<a href="#ch2Panel">Chapter 2</a>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<div>
|
||||
<div id="ch1Panel">Chapter 1 content goes here</div>
|
||||
<div id="ch2Panel">Chapter 2 content goes here</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**With ARIA (accessible):**
|
||||
|
||||
```html
|
||||
<ol role="tablist">
|
||||
<li id="ch1Tab" role="tab">
|
||||
<a href="#ch1Panel">Chapter 1</a>
|
||||
</li>
|
||||
<li id="ch2Tab" role="tab">
|
||||
<a href="#ch2Panel">Chapter 2</a>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<div>
|
||||
<div id="ch1Panel" role="tabpanel" aria-labelledby="ch1Tab">
|
||||
Chapter 1 content goes here
|
||||
</div>
|
||||
<div id="ch2Panel" role="tabpanel" aria-labelledby="ch2Tab">
|
||||
Chapter 2 content goes here
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Common ARIA State Attributes
|
||||
|
||||
| Attribute | Purpose |
|
||||
|-----------|---------|
|
||||
| `aria-checked` | State of checkbox or radio button |
|
||||
| `aria-disabled` | Visible but not editable/operable |
|
||||
| `aria-grabbed` | "Grabbed" state in drag-and-drop |
|
||||
| `aria-selected` | Selected state of an element |
|
||||
| `aria-expanded` | Whether expandable content is open |
|
||||
| `aria-pressed` | Pressed state of a toggle button |
|
||||
|
||||
Use ARIA states to indicate UI state and CSS attribute selectors to style
|
||||
accordingly.
|
||||
|
||||
### Visibility Management with `aria-hidden`
|
||||
|
||||
```html
|
||||
<div id="tp1" class="tooltip" role="tooltip" aria-hidden="true">
|
||||
Your first name is optional
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
div.tooltip[aria-hidden="true"] {
|
||||
display: none;
|
||||
}
|
||||
```
|
||||
|
||||
```javascript
|
||||
function showTip(el) {
|
||||
el.setAttribute("aria-hidden", "false");
|
||||
}
|
||||
```
|
||||
|
||||
### Role Changes
|
||||
|
||||
Never change an element's ARIA role dynamically. Instead, replace the element
|
||||
entirely:
|
||||
|
||||
```javascript
|
||||
// Correct: swap elements
|
||||
// View mode
|
||||
<div role="button">Edit this text</div>
|
||||
|
||||
// Edit mode: replace with an input
|
||||
<input type="text" />
|
||||
```
|
||||
|
||||
### Keyboard Navigation Best Practices
|
||||
|
||||
| Key | Expected Behavior |
|
||||
|-----|-------------------|
|
||||
| Tab / Shift+Tab | Move focus into and out of the widget |
|
||||
| Arrow Keys | Navigate between items within the widget |
|
||||
| Enter / Spacebar | Activate the focused control |
|
||||
| Escape | Close menus or dialogs |
|
||||
| Home / End | Jump to first or last item |
|
||||
|
||||
Focus management considerations:
|
||||
|
||||
- Maintain focus order that matches visual layout.
|
||||
- Use `tabindex="0"` to make custom elements keyboard accessible.
|
||||
- Avoid `tabindex > 0` (breaks natural tab order).
|
||||
- Update the visual focus indicator for keyboard users.
|
||||
- Move focus programmatically when opening dialogs or modals.
|
||||
|
||||
### Key ARIA Attributes for Interactive Widgets
|
||||
|
||||
**Labeling and Description:**
|
||||
|
||||
| Attribute | Usage |
|
||||
|-----------|-------|
|
||||
| `aria-label` | Direct text label |
|
||||
| `aria-labelledby` | References the element that labels this one |
|
||||
| `aria-describedby` | References additional descriptive text |
|
||||
| `aria-description` | Inline description text |
|
||||
|
||||
**Relationships:**
|
||||
|
||||
| Attribute | Usage |
|
||||
|-----------|-------|
|
||||
| `aria-controls` | This element controls another element |
|
||||
| `aria-owns` | Establishes parent-child relationships |
|
||||
| `aria-flowto` | Defines logical reading order |
|
||||
|
||||
**Widget Behavior:**
|
||||
|
||||
| Attribute | Usage |
|
||||
|-----------|-------|
|
||||
| `aria-haspopup` | Has a popup (menu, listbox, dialog, grid, tree) |
|
||||
| `aria-expanded` | Expandable content state (true/false) |
|
||||
| `aria-modal` | Modal dialog (true) |
|
||||
| `aria-live` | Live region announcements (polite, assertive, off) |
|
||||
| `aria-busy` | Loading or processing state (true/false) |
|
||||
|
||||
### Live Regions for Dynamic Content
|
||||
|
||||
```html
|
||||
<div aria-live="polite" aria-atomic="true">
|
||||
Updates will be announced to screen readers
|
||||
</div>
|
||||
```
|
||||
|
||||
- `aria-live="polite"` -- announce when convenient.
|
||||
- `aria-live="assertive"` -- announce immediately.
|
||||
- `aria-atomic="true"` -- announce the entire region, not just the changed part.
|
||||
|
||||
---
|
||||
|
||||
## 5. Mobile Accessibility Checklist
|
||||
|
||||
> **Source:** https://developer.mozilla.org/en-US/docs/Web/Accessibility/Guides/Mobile_accessibility_checklist
|
||||
|
||||
A checklist of accessibility requirements for mobile app developers targeting
|
||||
WCAG 2.2 AA compliance.
|
||||
|
||||
### Color
|
||||
|
||||
- **Normal text:** minimum 4.5:1 contrast ratio (less than 18pt or 14pt bold).
|
||||
- **Large text:** minimum 3:1 contrast ratio (at least 18pt or 14pt bold).
|
||||
- Information conveyed via color must also be available through other means (e.g.,
|
||||
underlines for links).
|
||||
|
||||
### Visibility
|
||||
|
||||
- Do NOT hide content exclusively with zero opacity, z-index ordering, or
|
||||
off-screen placement.
|
||||
- Use the `hidden` HTML attribute, `visibility`, or `display` CSS properties to
|
||||
truly hide content.
|
||||
- Avoid `aria-hidden` unless absolutely necessary.
|
||||
- Critical for single-page apps where multiple views/cards may overlap.
|
||||
|
||||
### Focus
|
||||
|
||||
- Standard controls (links, buttons, form fields) are focusable by default.
|
||||
- Custom controls must have an appropriate ARIA Role (e.g., `button`, `link`,
|
||||
`checkbox`).
|
||||
- Focus order must be logical and consistent.
|
||||
|
||||
### Text Equivalents
|
||||
|
||||
- Provide text alternatives for all non-text elements using `alt`, `title`,
|
||||
`aria-label`, `aria-labelledby`, or `aria-describedby`.
|
||||
- Avoid images of text.
|
||||
- Visible UI component text must match the programmatic name (WCAG 2.1: Label in
|
||||
Name).
|
||||
- All form controls must have associated `<label>` elements.
|
||||
|
||||
### Handling State
|
||||
|
||||
- Standard controls: the operating system handles radio buttons and checkboxes.
|
||||
- Custom controls must communicate state changes via ARIA States:
|
||||
- `aria-checked`
|
||||
- `aria-disabled`
|
||||
- `aria-selected`
|
||||
- `aria-expanded`
|
||||
- `aria-pressed`
|
||||
|
||||
### Orientation
|
||||
|
||||
- Content must not be restricted to portrait or landscape unless essential (e.g.,
|
||||
a piano app or bank-check scanner).
|
||||
- Reference: WCAG 2.1 Orientation (https://www.w3.org/WAI/WCAG21/Understanding/orientation.html).
|
||||
|
||||
### General Guidelines
|
||||
|
||||
**App Structure:**
|
||||
|
||||
- Always provide an app title.
|
||||
- Use a proper heading hierarchy without skipping levels:
|
||||
|
||||
```html
|
||||
<h1>Top level heading</h1>
|
||||
<h2>Secondary heading</h2>
|
||||
<h2>Another secondary heading</h2>
|
||||
<h3>Low level heading</h3>
|
||||
```
|
||||
|
||||
**ARIA Landmark Roles:**
|
||||
|
||||
Use landmarks to describe app or document structure:
|
||||
|
||||
- `banner`
|
||||
- `complementary`
|
||||
- `contentinfo`
|
||||
- `main`
|
||||
- `navigation`
|
||||
- `search`
|
||||
|
||||
**Touch Events (WCAG 2.1: Pointer Cancellation):**
|
||||
|
||||
1. Avoid executing functions on the down-event.
|
||||
2. If unavoidable, complete the function on the up-event with an abort mechanism.
|
||||
3. If unavoidable, ensure the up-event can undo the down-event action.
|
||||
4. Exceptions: game controls, virtual keyboards, real-time feedback.
|
||||
|
||||
**Touch Target Size:**
|
||||
|
||||
- Targets must be large enough for reliable user interaction.
|
||||
- Reference: BBC Mobile Accessibility Guidelines for specific sizing
|
||||
recommendations (https://www.bbc.co.uk/accessibility/forproducts/guides/mobile/target-touch-size).
|
||||
|
||||
---
|
||||
|
||||
## Additional Resources
|
||||
|
||||
| Resource | URL |
|
||||
|----------|-----|
|
||||
| W3C Accessibility Standards | https://www.w3.org/standards/webdesign/accessibility |
|
||||
| WAI Interest Group | https://www.w3.org/WAI/about/groups/waiig/ |
|
||||
| ARIA Specification | https://w3c.github.io/aria/ |
|
||||
| WAI-ARIA Authoring Practices | https://www.w3.org/WAI/ARIA/apg/ |
|
||||
| WCAG 2.1 Understanding Docs | https://www.w3.org/WAI/WCAG21/Understanding/ |
|
||||
| IBM Accessibility Requirements | https://www.ibm.com/able/requirements/requirements/ |
|
||||
| Accessibility Insights | https://accessibilityinsights.io/ |
|
||||
| WAVE Evaluation Tool | https://wave.webaim.org/extension/ |
|
||||
156
skills/create-web-form/references/aria-form-role.md
Normal file
156
skills/create-web-form/references/aria-form-role.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# ARIA Form Role Reference
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/form_role>
|
||||
|
||||
## Definition and Description
|
||||
|
||||
The `form` role identifies a group of elements on a page that provide equivalent functionality to an HTML form. It is a **landmark role** that helps users navigate to form sections.
|
||||
|
||||
A `form` landmark identifies a region of content that contains a collection of items and objects that, as a whole, combine to create a form when no other named landmark is appropriate (e.g., `main` or `search`).
|
||||
|
||||
**Important:** The form is not exposed as a landmark region unless it has an accessible name.
|
||||
|
||||
## Preferred Approach: Use HTML `<form>` Instead
|
||||
|
||||
Use an HTML `<form>` element to contain your form controls, rather than the ARIA `form` role, unless you have a very good reason. The HTML `<form>` element is sufficient to tell assistive technologies that there is a form.
|
||||
|
||||
```html
|
||||
<!-- Recommended semantic approach -->
|
||||
<form id="send-comment" aria-label="Add a comment">
|
||||
<!-- form controls here -->
|
||||
</form>
|
||||
```
|
||||
|
||||
The `<form>` element will automatically communicate as a `form` landmark if provided an accessible name.
|
||||
|
||||
## When to Use `role="form"`
|
||||
|
||||
The `form` role should be used to identify a **region of the page** containing form content, not individual form fields. It is appropriate when you are not using a native `<form>` element but still want to convey form semantics to assistive technologies.
|
||||
|
||||
### Basic Example
|
||||
|
||||
```html
|
||||
<div role="form" id="contact-info" aria-label="Contact information">
|
||||
<!-- form content -->
|
||||
</div>
|
||||
```
|
||||
|
||||
### Full Example with Form Controls
|
||||
|
||||
```html
|
||||
<div role="form" id="send-comment" aria-label="Add a comment">
|
||||
<label for="username">Username</label>
|
||||
<input
|
||||
id="username"
|
||||
name="username"
|
||||
autocomplete="nickname"
|
||||
autocorrect="off"
|
||||
type="text" />
|
||||
|
||||
<label for="email">Email</label>
|
||||
<input
|
||||
id="email"
|
||||
name="email"
|
||||
autocomplete="email"
|
||||
autocapitalize="off"
|
||||
autocorrect="off"
|
||||
spellcheck="false"
|
||||
type="text" />
|
||||
|
||||
<label for="comment">Comment</label>
|
||||
<textarea id="comment" name="comment"></textarea>
|
||||
|
||||
<input value="Comment" type="submit" />
|
||||
</div>
|
||||
```
|
||||
|
||||
## Accessible Naming (Required for Landmark Exposure)
|
||||
|
||||
Each `<form>` element and form `role` that needs to be exposed as a landmark **must be given an accessible name** using one of:
|
||||
|
||||
- `aria-label`
|
||||
- `aria-labelledby`
|
||||
- `title` attribute
|
||||
|
||||
### Example with `aria-label`
|
||||
|
||||
```html
|
||||
<div role="form" id="gift-cards" aria-label="Purchase a gift card">
|
||||
<!-- form content -->
|
||||
</div>
|
||||
```
|
||||
|
||||
### Avoid Redundant Descriptions
|
||||
|
||||
Screen readers announce the role type, so do not repeat it in the label:
|
||||
|
||||
- **Incorrect:** `aria-label="Contact form"` (announces "contact form form")
|
||||
- **Correct:** `aria-label="Contact information"` (concise and non-redundant)
|
||||
|
||||
## Attributes and Interactions
|
||||
|
||||
### Associated WAI-ARIA Roles, States, and Properties
|
||||
|
||||
No role-specific states or properties are defined for the `form` role.
|
||||
|
||||
### Keyboard Interactions
|
||||
|
||||
No role-specific keyboard interactions are defined for the `form` role.
|
||||
|
||||
### Required JavaScript Features
|
||||
|
||||
- **`onsubmit` Event Handler:** Handles events raised when the form is submitted.
|
||||
- Anything that is not a native `<form>` element cannot be submitted using standard form submission. You must use JavaScript to build alternative data submission mechanisms (e.g., with `fetch()` or `XMLHttpRequest`).
|
||||
|
||||
## Accessibility Concerns
|
||||
|
||||
### 1. Use Sparingly
|
||||
|
||||
Landmark roles are intended for larger overall sections of the document. Using too many landmark roles creates "noise" in screen readers, making it difficult for users to understand the overall page layout.
|
||||
|
||||
### 2. Inputs Are Not Forms
|
||||
|
||||
Do not declare `role="form"` on individual form elements (inputs, textareas, selects, etc.). Apply the role to the **wrapper element only**.
|
||||
|
||||
```html
|
||||
<!-- Incorrect -->
|
||||
<input role="form" type="text" />
|
||||
|
||||
<!-- Correct -->
|
||||
<div role="form" aria-label="User details">
|
||||
<input type="text" />
|
||||
</div>
|
||||
```
|
||||
|
||||
### 3. Use `search` Role for Search Forms
|
||||
|
||||
If a form is used for search functionality, use the more specialized `role="search"` instead of `role="form"`.
|
||||
|
||||
### 4. Use Native Form Controls
|
||||
|
||||
Even when using `role="form"`, prefer native HTML form controls:
|
||||
|
||||
- `<button>`
|
||||
- `<input>`
|
||||
- `<select>`
|
||||
- `<textarea>`
|
||||
- `<label>`
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Prefer the HTML `<form>` element.** Using the semantic `<form>` element automatically communicates the form landmark without needing ARIA.
|
||||
- **Provide unique labels.** Each form in a document should have a unique accessible name to help users understand its purpose.
|
||||
- **Make labels visible.** Labels should be visible to all users, not just assistive technology users.
|
||||
- **Use appropriate landmark roles.** Use `role="search"` for search forms, `role="form"` for general form groups, and the `<form>` HTML element whenever possible.
|
||||
|
||||
## Specifications
|
||||
|
||||
- [WAI-ARIA: form role specification](https://w3c.github.io/aria/#form)
|
||||
- [WAI-ARIA APG: Form landmark example](https://www.w3.org/WAI/ARIA/apg/patterns/landmarks/examples/form.html)
|
||||
|
||||
## Related References
|
||||
|
||||
- [`<form>` HTML element (MDN)](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/form)
|
||||
- [`<legend>` HTML element (MDN)](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/legend)
|
||||
- [`<label>` HTML element (MDN)](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/label)
|
||||
- [`search` ARIA role (MDN)](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/search_role)
|
||||
1027
skills/create-web-form/references/css-styling.md
Normal file
1027
skills/create-web-form/references/css-styling.md
Normal file
File diff suppressed because it is too large
Load Diff
451
skills/create-web-form/references/form-basics.md
Normal file
451
skills/create-web-form/references/form-basics.md
Normal file
@@ -0,0 +1,451 @@
|
||||
# Form Basics Reference
|
||||
|
||||
This reference consolidates key educational content from MDN Web Docs covering the fundamentals of creating and structuring HTML web forms.
|
||||
|
||||
---
|
||||
|
||||
## Your First Form
|
||||
|
||||
> **Source:** https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Forms/Your_first_form
|
||||
|
||||
### What Are Web Forms?
|
||||
|
||||
Web forms are one of the main points of interaction between users and websites or applications. They allow users to enter data for server processing and storage, or to update the interface immediately on the client side.
|
||||
|
||||
A web form consists of:
|
||||
|
||||
- **Form controls (widgets):** text fields, dropdowns, buttons, checkboxes, radio buttons
|
||||
- **Additional elements:** mostly built with the `<input>` element, plus other semantic elements
|
||||
- **Form labels:** paired with controls for accessibility
|
||||
|
||||
Form controls can enforce specific formats via **form validation** and should be paired with text labels for both sighted and visually impaired users.
|
||||
|
||||
### Designing Your Form
|
||||
|
||||
Best practices before writing any code:
|
||||
|
||||
- Step back and plan your form before coding
|
||||
- Create a mockup to define the data you need
|
||||
- Keep forms simple and focused
|
||||
- Ask only for absolutely necessary data
|
||||
- Larger forms risk frustrating users and losing engagement
|
||||
|
||||
### The `<form>` Element
|
||||
|
||||
The `<form>` element formally defines a form container and its behavior.
|
||||
|
||||
```html
|
||||
<form action="/my-handling-form-page" method="post">...</form>
|
||||
```
|
||||
|
||||
**Attributes:**
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `action` | The URL where form data is sent when submitted |
|
||||
| `method` | The HTTP method for sending data (`get` or `post`) |
|
||||
|
||||
Both attributes are optional but it is standard practice to always set them.
|
||||
|
||||
### The `<label>`, `<input>`, and `<textarea>` Elements
|
||||
|
||||
```html
|
||||
<form action="/my-handling-form-page" method="post">
|
||||
<p>
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" id="name" name="user_name" />
|
||||
</p>
|
||||
<p>
|
||||
<label for="mail">Email:</label>
|
||||
<input type="email" id="mail" name="user_email" />
|
||||
</p>
|
||||
<p>
|
||||
<label for="msg">Message:</label>
|
||||
<textarea id="msg" name="user_message"></textarea>
|
||||
</p>
|
||||
</form>
|
||||
```
|
||||
|
||||
#### The `<label>` Element
|
||||
|
||||
- The `for` attribute must match the `id` of its associated form control.
|
||||
- Clicking or tapping a label activates its associated control.
|
||||
- Provides an accessible name for screen readers.
|
||||
- Improves usability for mouse, trackpad, and touch devices.
|
||||
|
||||
#### The `<input>` Element
|
||||
|
||||
The `type` attribute defines how the input appears and behaves.
|
||||
|
||||
| Type | Description |
|
||||
|---------|-------------|
|
||||
| `text` | Basic single-line text field (default); accepts any text |
|
||||
| `email` | Single-line field that validates for well-formed email addresses; shows an appropriate keyboard on mobile devices |
|
||||
|
||||
`<input>` is a **void element** -- it has no closing tag.
|
||||
|
||||
Setting a default value:
|
||||
|
||||
```html
|
||||
<input type="text" value="by default this element is filled with this text" />
|
||||
```
|
||||
|
||||
#### The `<textarea>` Element
|
||||
|
||||
A multi-line text field for longer messages. Unlike `<input>`, it is **not** a void element and requires a closing tag.
|
||||
|
||||
Setting a default value:
|
||||
|
||||
```html
|
||||
<textarea>
|
||||
by default this element is filled with this text
|
||||
</textarea>
|
||||
```
|
||||
|
||||
### The `<button>` Element
|
||||
|
||||
```html
|
||||
<p class="button">
|
||||
<button type="submit">Send your message</button>
|
||||
</p>
|
||||
```
|
||||
|
||||
**`type` attribute values:**
|
||||
|
||||
| Value | Description |
|
||||
|----------|-------------|
|
||||
| `submit` | Sends form data to the URL defined in in the `<form>` element's `action` attribute (default) |
|
||||
| `reset` | Resets all widgets to their default values (considered a UX anti-pattern -- avoid unless necessary) |
|
||||
| `button` | Does nothing by default; useful for custom JavaScript functionality |
|
||||
|
||||
The `<button>` element is preferred over `<input type="submit">` because `<button>` allows full HTML content inside it, enabling more complex designs, while `<input>` only allows plain text.
|
||||
|
||||
### Basic Form Styling
|
||||
|
||||
```css
|
||||
body {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
form {
|
||||
display: inline-block;
|
||||
padding: 1em;
|
||||
border: 1px solid #cccccc;
|
||||
border-radius: 1em;
|
||||
}
|
||||
|
||||
p + p {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
min-width: 90px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
font: 1em sans-serif;
|
||||
width: 300px;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #999999;
|
||||
}
|
||||
|
||||
input:focus,
|
||||
textarea:focus {
|
||||
outline-style: solid;
|
||||
outline-color: black;
|
||||
}
|
||||
|
||||
textarea {
|
||||
vertical-align: top;
|
||||
height: 5em;
|
||||
}
|
||||
|
||||
.button {
|
||||
padding-left: 90px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
```
|
||||
|
||||
### Sending Form Data to Your Web Server
|
||||
|
||||
Form data is sent as **name/value pairs**. Every form control that should submit data must have a `name` attribute.
|
||||
|
||||
```html
|
||||
<form action="/my-handling-form-page" method="post">
|
||||
<input type="text" id="name" name="user_name" />
|
||||
<input type="email" id="mail" name="user_email" />
|
||||
<textarea id="msg" name="user_message"></textarea>
|
||||
<button type="submit">Send your message</button>
|
||||
</form>
|
||||
```
|
||||
|
||||
This form sends three pieces of data to `/my-handling-form-page` via HTTP POST:
|
||||
|
||||
- `user_name` -- the user's name
|
||||
- `user_email` -- the user's email
|
||||
- `user_message` -- the user's message
|
||||
|
||||
Each server-side language (PHP, Python, Ruby, Java, C#, etc.) has its own mechanism for handling form data using the `name` attributes.
|
||||
|
||||
### Complete Example
|
||||
|
||||
```html
|
||||
<form action="/my-handling-form-page" method="post">
|
||||
<div>
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" id="name" name="user_name" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="mail">Email:</label>
|
||||
<input type="email" id="mail" name="user_email" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="msg">Message:</label>
|
||||
<textarea id="msg" name="user_message"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="button">
|
||||
<button type="submit">Send your message</button>
|
||||
</div>
|
||||
</form>
|
||||
```
|
||||
|
||||
### Key Takeaways
|
||||
|
||||
1. **Accessibility first:** Always use `<label>` elements with `for` attributes.
|
||||
2. **Semantic HTML:** Use appropriate `<input>` types (email, text, etc.).
|
||||
3. **Keep it simple:** Ask only for necessary data.
|
||||
4. **Name your controls:** Every input needs a `name` attribute for form submission.
|
||||
5. **Styling matters:** Forms need CSS to look professional.
|
||||
|
||||
---
|
||||
|
||||
## How to Structure a Web Form
|
||||
|
||||
> **Source:** https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Forms/How_to_structure_a_web_form
|
||||
|
||||
### The `<form>` Element
|
||||
|
||||
The `<form>` element formally defines a form and determines its behavior.
|
||||
|
||||
Key points:
|
||||
|
||||
- All form content must be nested inside `<form>`.
|
||||
- Assistive technologies and browser plugins can discover `<form>` elements and provide special features.
|
||||
- **It is strictly forbidden to nest a form inside another form** -- doing so causes unpredictable behavior.
|
||||
- Form controls can exist outside a `<form>` element but should be associated using the `form` attribute.
|
||||
|
||||
### The `<fieldset>` and `<legend>` Elements
|
||||
|
||||
`<fieldset>` creates groups of widgets for styling and semantic purposes. `<legend>` labels a fieldset by describing its purpose and is positioned directly after the opening `<fieldset>` tag.
|
||||
|
||||
Many assistive technologies (such as JAWS and NVDA) treat the legend text as part of each control's label within the fieldset.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<fieldset>
|
||||
<legend>Fruit juice size</legend>
|
||||
<p>
|
||||
<input type="radio" name="size" id="size_1" value="small" />
|
||||
<label for="size_1">Small</label>
|
||||
</p>
|
||||
<p>
|
||||
<input type="radio" name="size" id="size_2" value="medium" />
|
||||
<label for="size_2">Medium</label>
|
||||
</p>
|
||||
<p>
|
||||
<input type="radio" name="size" id="size_3" value="large" />
|
||||
<label for="size_3">Large</label>
|
||||
</p>
|
||||
</fieldset>
|
||||
</form>
|
||||
```
|
||||
|
||||
A screen reader would announce: "Fruit juice size small," "Fruit juice size medium," "Fruit juice size large."
|
||||
|
||||
**Use cases:**
|
||||
|
||||
- Essential for grouping radio buttons
|
||||
- Sectioning complex, long forms across multiple pages
|
||||
- Improving usability when many controls appear on a single page
|
||||
|
||||
### The `<label>` Element
|
||||
|
||||
The `<label>` element is the formal way to define a label for an HTML form widget.
|
||||
|
||||
#### Two Methods for Associating Labels
|
||||
|
||||
**Method 1: Using the `for` attribute (recommended)**
|
||||
|
||||
```html
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" id="name" name="user_name" />
|
||||
```
|
||||
|
||||
A screen reader would announce: "Name, edit text."
|
||||
|
||||
**Method 2: Implicit association (nesting)**
|
||||
|
||||
```html
|
||||
<label for="name">
|
||||
Name: <input type="text" id="name" name="user_name" />
|
||||
</label>
|
||||
```
|
||||
|
||||
**Best practice:** Always set the `for` attribute even when nesting, to ensure all assistive technologies understand the relationship.
|
||||
|
||||
#### Labels Are Clickable
|
||||
|
||||
Clicking or tapping a label activates the corresponding widget. This is especially useful for radio buttons and checkboxes which have small hit areas.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<p>
|
||||
<input type="checkbox" id="taste_1" name="taste_cherry" value="cherry" />
|
||||
<label for="taste_1">I like cherry</label>
|
||||
</p>
|
||||
<p>
|
||||
<input type="checkbox" id="taste_2" name="taste_banana" value="banana" />
|
||||
<label for="taste_2">I like banana</label>
|
||||
</p>
|
||||
</form>
|
||||
```
|
||||
|
||||
#### Handling Multiple Labels
|
||||
|
||||
Avoid placing multiple separate labels on one widget. Instead, include all label information in one `<label>` element:
|
||||
|
||||
```html
|
||||
<div>
|
||||
<label for="username">Name *:</label>
|
||||
<input id="username" type="text" name="username" required />
|
||||
</div>
|
||||
```
|
||||
|
||||
### Common HTML Structures Used with Forms
|
||||
|
||||
Recommended structural elements for organizing form content:
|
||||
|
||||
- `<ul>` or `<ol>` lists with `<li>` items -- best for multiple checkboxes or radio buttons
|
||||
- `<p>` and `<div>` elements for wrapping labels and widgets
|
||||
- `<section>` elements to organize complex forms into logical groups
|
||||
- HTML headings (`<h1>`, `<h2>`, etc.) for sectioning
|
||||
- If a form has required fields, include a statement explaining the notation (e.g., "* required") before the form begins
|
||||
|
||||
### Building a Form Structure -- Payment Form Example
|
||||
|
||||
```html
|
||||
<form>
|
||||
<h1>Payment form</h1>
|
||||
<p>Please complete all required (*) fields.</p>
|
||||
|
||||
<!-- Contact Information Section -->
|
||||
<section>
|
||||
<h2>Contact information</h2>
|
||||
<fieldset>
|
||||
<legend>Title</legend>
|
||||
<ul>
|
||||
<li>
|
||||
<label for="title_1">
|
||||
<input type="radio" id="title_1" name="title" value="A" />
|
||||
Ace
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label for="title_2">
|
||||
<input type="radio" id="title_2" name="title" value="K" />
|
||||
King
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label for="title_3">
|
||||
<input type="radio" id="title_3" name="title" value="Q" />
|
||||
Queen
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
</fieldset>
|
||||
<p>
|
||||
<label for="name">Name *:</label>
|
||||
<input type="text" id="name" name="username" required />
|
||||
</p>
|
||||
<p>
|
||||
<label for="mail">Email *:</label>
|
||||
<input type="email" id="mail" name="user-mail" required />
|
||||
</p>
|
||||
<p>
|
||||
<label for="pwd">Password *:</label>
|
||||
<input type="password" id="pwd" name="password" required />
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<!-- Payment Information Section -->
|
||||
<section>
|
||||
<h2>Payment information</h2>
|
||||
<p>
|
||||
<label for="card">
|
||||
<span>Card type:</span>
|
||||
</label>
|
||||
<select id="card" name="user-card">
|
||||
<option value="visa">Visa</option>
|
||||
<option value="mc">Mastercard</option>
|
||||
<option value="amex">American Express</option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label for="number">Card number *:</label>
|
||||
<input type="tel" id="number" name="card-number" required />
|
||||
</p>
|
||||
<p>
|
||||
<label for="expiration">Expiration date *:</label>
|
||||
<input
|
||||
type="text"
|
||||
id="expiration"
|
||||
name="expiration"
|
||||
required
|
||||
placeholder="MM/YY"
|
||||
pattern="^(0[1-9]|1[0-2])\/([0-9]{2})$" />
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<!-- Submit Section -->
|
||||
<section>
|
||||
<p>
|
||||
<button type="submit">Validate the payment</button>
|
||||
</p>
|
||||
</section>
|
||||
</form>
|
||||
```
|
||||
|
||||
### Important Attributes Reference
|
||||
|
||||
| Attribute | Element | Purpose |
|
||||
|---------------|----------------|---------|
|
||||
| `for` | `<label>` | Associates a label with a form control by matching the control's `id` |
|
||||
| `id` | Form control | Unique identifier for associating with labels |
|
||||
| `name` | Form control | Identifies data submitted with the form |
|
||||
| `required` | Form control | Marks a field as required for submission |
|
||||
| `placeholder` | `<input>` | Shows example format inside the field (e.g., "MM/YY") |
|
||||
| `pattern` | `<input>` | Regular expression for client-side validation |
|
||||
| `form` | Form control | Associates a control with a `<form>`, even if the control is outside it |
|
||||
| `type` | `<input>`, `<button>` | Specifies input behavior (text, email, password, tel, etc.) |
|
||||
|
||||
### Key Best Practices for Accessible Form Structure
|
||||
|
||||
1. Always use the `<form>` element to wrap all form content.
|
||||
2. Use `<fieldset>` and `<legend>` to group related controls, especially radio buttons.
|
||||
3. Always associate labels with form controls using the `for` attribute pointing to the control's `id`.
|
||||
4. Use semantic HTML (`<section>`, headings) to organize complex forms.
|
||||
5. State required-field notation upfront in a paragraph before the form.
|
||||
6. Use lists (`<ul>`/`<ol>`) for multiple checkboxes or radio buttons.
|
||||
7. Test with screen readers to verify accessibility.
|
||||
8. Never nest forms inside other forms.
|
||||
9. Make labels clickable to increase hit areas for checkbox and radio button controls.
|
||||
851
skills/create-web-form/references/form-controls.md
Normal file
851
skills/create-web-form/references/form-controls.md
Normal file
@@ -0,0 +1,851 @@
|
||||
# Form Controls Reference
|
||||
|
||||
A consolidated reference guide covering HTML form structure, native form controls, HTML5 input types, and additional form elements. Content sourced from the Mozilla Developer Network (MDN) Web Docs.
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [How to Structure a Web Form](#how-to-structure-a-web-form)
|
||||
2. [Basic Native Form Controls](#basic-native-form-controls)
|
||||
3. [HTML5 Input Types](#html5-input-types)
|
||||
4. [Other Form Controls](#other-form-controls)
|
||||
|
||||
---
|
||||
|
||||
## How to Structure a Web Form
|
||||
|
||||
> **Source:** https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Forms/How_to_structure_a_web_form
|
||||
|
||||
### The `<form>` Element
|
||||
|
||||
The `<form>` element formally defines a form and determines its behavior. It must wrap all form contents.
|
||||
|
||||
**Important:** Never nest a form inside another form -- this causes unpredictable behavior.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<!-- form contents -->
|
||||
</form>
|
||||
```
|
||||
|
||||
Form controls can exist outside a `<form>` element using the `form` attribute to associate them with a specific form by its ID.
|
||||
|
||||
### Grouping and Semantic Structure
|
||||
|
||||
#### The `<fieldset>` and `<legend>` Elements
|
||||
|
||||
`<fieldset>` groups widgets that share the same purpose, improving usability and accessibility. `<legend>` provides a descriptive label for the fieldset.
|
||||
|
||||
**Key Benefits:**
|
||||
- Screen readers (like JAWS and NVDA) speak the legend before each control inside the fieldset
|
||||
- Essential for grouping radio buttons and checkboxes
|
||||
- Useful for sectioning long forms across multiple pages
|
||||
|
||||
```html
|
||||
<form>
|
||||
<fieldset>
|
||||
<legend>Fruit juice size</legend>
|
||||
<p>
|
||||
<input type="radio" name="size" id="size_1" value="small" />
|
||||
<label for="size_1">Small</label>
|
||||
</p>
|
||||
<p>
|
||||
<input type="radio" name="size" id="size_2" value="medium" />
|
||||
<label for="size_2">Medium</label>
|
||||
</p>
|
||||
<p>
|
||||
<input type="radio" name="size" id="size_3" value="large" />
|
||||
<label for="size_3">Large</label>
|
||||
</p>
|
||||
</fieldset>
|
||||
</form>
|
||||
```
|
||||
|
||||
**Result:** Screen readers announce: "Fruit juice size small," "Fruit juice size medium," "Fruit juice size large"
|
||||
|
||||
### Labels: The Foundation of Accessibility
|
||||
|
||||
#### The `<label>` Element
|
||||
|
||||
Labels formally associate text with form controls. The `for` attribute connects a label to its input via the input's `id`.
|
||||
|
||||
```html
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" id="name" name="user_name" />
|
||||
```
|
||||
|
||||
**Implicit Association:** Nest the control inside the label (though explicit `for` attribute is still best practice):
|
||||
|
||||
```html
|
||||
<label for="name">
|
||||
Name: <input type="text" id="name" name="user_name" />
|
||||
</label>
|
||||
```
|
||||
|
||||
**Accessibility Impact:**
|
||||
- Screen readers announce: "Name, edit text"
|
||||
- Without proper labels: "Edit text blank" (not helpful)
|
||||
|
||||
#### Labels Are Clickable
|
||||
|
||||
Clicking or tapping a label activates its associated control -- especially useful for checkboxes and radio buttons with small hit areas.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<p>
|
||||
<input type="checkbox" id="taste_1" name="taste_cherry" value="cherry" />
|
||||
<label for="taste_1">I like cherry</label>
|
||||
</p>
|
||||
</form>
|
||||
```
|
||||
|
||||
#### Multiple Labels (Best Practices)
|
||||
|
||||
Avoid putting multiple labels on a single widget. Instead, include all text within one label:
|
||||
|
||||
```html
|
||||
<!-- Not recommended -->
|
||||
<label for="username">Name:</label>
|
||||
<input id="username" type="text" name="username" required />
|
||||
<label for="username">*</label>
|
||||
|
||||
<!-- Better -->
|
||||
<label for="username">
|
||||
<span>Name:</span>
|
||||
<input id="username" type="text" name="username" required />
|
||||
<span>*</span>
|
||||
</label>
|
||||
|
||||
<!-- Best -->
|
||||
<label for="username">Name *:</label>
|
||||
<input id="username" type="text" name="username" required />
|
||||
```
|
||||
|
||||
### Common HTML Structures with Forms
|
||||
|
||||
Use these semantic HTML elements to structure forms:
|
||||
|
||||
- `<ul>` / `<ol>` with `<li>`: Recommended for grouping checkboxes or radio buttons
|
||||
- `<p>`: Wrap label-control pairs
|
||||
- `<div>`: General grouping
|
||||
- `<section>`: Group related form sections
|
||||
- `<h1>`, `<h2>`: Organize complex forms into sections
|
||||
|
||||
### Complete Payment Form Example
|
||||
|
||||
```html
|
||||
<form>
|
||||
<h1>Payment form</h1>
|
||||
<p>Please complete all required (*) fields.</p>
|
||||
|
||||
<!-- Contact Information Section -->
|
||||
<section>
|
||||
<h2>Contact information</h2>
|
||||
|
||||
<fieldset>
|
||||
<legend>Title</legend>
|
||||
<ul>
|
||||
<li>
|
||||
<label for="title_1">
|
||||
<input type="radio" id="title_1" name="title" value="A" />
|
||||
Ace
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label for="title_2">
|
||||
<input type="radio" id="title_2" name="title" value="K" />
|
||||
King
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
</fieldset>
|
||||
|
||||
<p>
|
||||
<label for="name">Name *:</label>
|
||||
<input type="text" id="name" name="username" required />
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="mail">Email *:</label>
|
||||
<input type="email" id="mail" name="user-mail" required />
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="pwd">Password *:</label>
|
||||
<input type="password" id="pwd" name="password" required />
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<!-- Payment Information Section -->
|
||||
<section>
|
||||
<h2>Payment information</h2>
|
||||
|
||||
<p>
|
||||
<label for="card">Card type:</label>
|
||||
<select id="card" name="user-card">
|
||||
<option value="visa">Visa</option>
|
||||
<option value="mc">Mastercard</option>
|
||||
<option value="amex">American Express</option>
|
||||
</select>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="number">Card number *:</label>
|
||||
<input type="tel" id="number" name="card-number" required />
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<!-- Submit Section -->
|
||||
<section>
|
||||
<p>
|
||||
<button type="submit">Validate the payment</button>
|
||||
</p>
|
||||
</section>
|
||||
</form>
|
||||
```
|
||||
|
||||
### Form Structure Best Practices
|
||||
|
||||
| Practice | Benefit |
|
||||
|----------|---------|
|
||||
| Always use `<form>` wrapper | Recognized by assistive tech and browser plugins |
|
||||
| Wrap related controls in `<fieldset>` with `<legend>` | Improves usability and accessibility |
|
||||
| Always associate labels with `for` attribute | Screen readers announce label with control |
|
||||
| Use semantic HTML (`<section>`, `<h2>`, etc.) | Better form structure and accessibility |
|
||||
| Group radio buttons/checkboxes in lists | Clearer visual and semantic organization |
|
||||
| Indicate required fields clearly | Users and AT know which fields are mandatory |
|
||||
| Test with screen readers | Verify the form is truly accessible |
|
||||
|
||||
---
|
||||
|
||||
## Basic Native Form Controls
|
||||
|
||||
> **Source:** https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Forms/Basic_native_form_controls
|
||||
|
||||
### Text Input Fields
|
||||
|
||||
#### Single Line Text Fields
|
||||
|
||||
Created with `<input type="text">` or omitting the type attribute (text is the default).
|
||||
|
||||
```html
|
||||
<input type="text" id="comment" name="comment" value="I'm a text field" />
|
||||
```
|
||||
|
||||
**Common text field behaviors:**
|
||||
- Can be marked as `readonly` (value shown but not modifiable, still sent in form submission) or `disabled` (not sent with form)
|
||||
- Support `placeholder` attribute for brief descriptions
|
||||
- Can be constrained with `size` (physical box size) and `maxlength` (character limit)
|
||||
- Benefit from `spellcheck` attribute
|
||||
- Remove line breaks automatically before sending to server
|
||||
|
||||
#### Password Field
|
||||
|
||||
Obscures input characters (shown as dots or asterisks) for security.
|
||||
|
||||
```html
|
||||
<input type="password" id="pwd" name="pwd" />
|
||||
```
|
||||
|
||||
**Security Note:** This only hides the text visually. Always use HTTPS for secure form transmission to prevent data interception.
|
||||
|
||||
#### Hidden Content
|
||||
|
||||
Invisible form control sent with form data (e.g., timestamps, tracking information).
|
||||
|
||||
```html
|
||||
<input type="hidden" id="timestamp" name="timestamp" value="1286705410" />
|
||||
```
|
||||
|
||||
- Not visible to users
|
||||
- Never receives focus
|
||||
- Cannot be intentionally edited by users
|
||||
- Screen readers will not notice it
|
||||
- Must have `name` and `value` attributes
|
||||
|
||||
### Checkable Items: Checkboxes and Radio Buttons
|
||||
|
||||
#### Checkbox
|
||||
|
||||
Multiple selections allowed. Each checkbox can be independently checked or unchecked.
|
||||
|
||||
```html
|
||||
<fieldset>
|
||||
<legend>Choose all the vegetables you like to eat</legend>
|
||||
<ul>
|
||||
<li>
|
||||
<label for="carrots">Carrots</label>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="carrots"
|
||||
name="vegetable"
|
||||
value="carrots"
|
||||
checked />
|
||||
</li>
|
||||
<li>
|
||||
<label for="peas">Peas</label>
|
||||
<input type="checkbox" id="peas" name="vegetable" value="peas" />
|
||||
</li>
|
||||
<li>
|
||||
<label for="cabbage">Cabbage</label>
|
||||
<input type="checkbox" id="cabbage" name="vegetable" value="cabbage" />
|
||||
</li>
|
||||
</ul>
|
||||
</fieldset>
|
||||
```
|
||||
|
||||
**Properties:**
|
||||
- Use same `name` attribute for related checkboxes
|
||||
- Include `checked` attribute to pre-select
|
||||
- Only values of checked boxes are sent with form
|
||||
|
||||
#### Radio Button
|
||||
|
||||
Only one selection allowed per group. Tied together by the same `name` attribute.
|
||||
|
||||
```html
|
||||
<fieldset>
|
||||
<legend>What is your favorite meal?</legend>
|
||||
<ul>
|
||||
<li>
|
||||
<label for="soup">Soup</label>
|
||||
<input type="radio" id="soup" name="meal" value="soup" checked />
|
||||
</li>
|
||||
<li>
|
||||
<label for="curry">Curry</label>
|
||||
<input type="radio" id="curry" name="meal" value="curry" />
|
||||
</li>
|
||||
<li>
|
||||
<label for="pizza">Pizza</label>
|
||||
<input type="radio" id="pizza" name="meal" value="pizza" />
|
||||
</li>
|
||||
</ul>
|
||||
</fieldset>
|
||||
```
|
||||
|
||||
**Properties:**
|
||||
- Buttons in same group share `name` attribute
|
||||
- Checking one automatically unchecks others
|
||||
- Only checked value is sent with form
|
||||
- Cannot uncheck all without resetting form
|
||||
|
||||
**Accessibility Best Practice:** Wrap related items in `<fieldset>` with `<legend>` describing the group, and place each `<label>`/`<input>` pair together.
|
||||
|
||||
### Buttons
|
||||
|
||||
#### Submit Button
|
||||
|
||||
Sends form data to server.
|
||||
|
||||
```html
|
||||
<!-- Using <input> -->
|
||||
<input type="submit" value="Submit this form" />
|
||||
|
||||
<!-- Using <button> -->
|
||||
<button type="submit">Submit this form</button>
|
||||
```
|
||||
|
||||
#### Reset Button
|
||||
|
||||
Resets all form widgets to default values.
|
||||
|
||||
```html
|
||||
<!-- Using <input> -->
|
||||
<input type="reset" value="Reset this form" />
|
||||
|
||||
<!-- Using <button> -->
|
||||
<button type="reset">Reset this form</button>
|
||||
```
|
||||
|
||||
#### Anonymous Button
|
||||
|
||||
No automatic effect; requires JavaScript customization.
|
||||
|
||||
```html
|
||||
<!-- Using <input> -->
|
||||
<input type="button" value="Do Nothing without JavaScript" />
|
||||
|
||||
<!-- Using <button> -->
|
||||
<button type="button">Do Nothing without JavaScript</button>
|
||||
```
|
||||
|
||||
**Advantage of `<button>` elements:** Much easier to style and supports HTML content inside tags.
|
||||
|
||||
### Image Button
|
||||
|
||||
Renders as an image but behaves as a submit button. Submits X and Y coordinates of click.
|
||||
|
||||
```html
|
||||
<input type="image" alt="Click me!" src="my-img.png" width="80" height="30" />
|
||||
```
|
||||
|
||||
**Coordinate Submission:**
|
||||
- X coordinate key: `[name].x`
|
||||
- Y coordinate key: `[name].y`
|
||||
|
||||
**Example URL with GET method:**
|
||||
```
|
||||
https://example.com?pos.x=123&pos.y=456
|
||||
```
|
||||
|
||||
### File Picker
|
||||
|
||||
Allows users to select one or more files to send to server.
|
||||
|
||||
```html
|
||||
<!-- Single file -->
|
||||
<input type="file" name="file" id="file" accept="image/*" />
|
||||
|
||||
<!-- Multiple files -->
|
||||
<input type="file" name="file" id="file" accept="image/*" multiple />
|
||||
```
|
||||
|
||||
**Mobile Device Capture** -- access device camera, microphone, or storage directly:
|
||||
|
||||
```html
|
||||
<input type="file" accept="image/*;capture=camera" />
|
||||
<input type="file" accept="video/*;capture=camcorder" />
|
||||
<input type="file" accept="audio/*;capture=microphone" />
|
||||
```
|
||||
|
||||
**Attributes:**
|
||||
- `accept`: Constrains file types (e.g., `image/*`, `.pdf`)
|
||||
- `multiple`: Allows selecting multiple files
|
||||
|
||||
### Common Attributes for All Form Controls
|
||||
|
||||
| Attribute | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `autofocus` | false | Element automatically receives focus when page loads (only one per document) |
|
||||
| `disabled` | false | User cannot interact; inherits from containing `<fieldset>` if applicable |
|
||||
| `form` | -- | Associates control with `<form>` element by ID (allows control outside form) |
|
||||
| `name` | -- | Control name; submitted with form data |
|
||||
| `value` | -- | Element's initial value |
|
||||
|
||||
### Form Data Submission Behavior
|
||||
|
||||
**Checkable Items Special Case:**
|
||||
- Values sent only if checked
|
||||
- Unchecked items: nothing is sent (not even name)
|
||||
- Checked but no value attribute: name is sent with value of `"on"`
|
||||
|
||||
```html
|
||||
<input type="checkbox" name="subscribe" value="yes" />
|
||||
```
|
||||
- If checked: `subscribe=yes`
|
||||
- If unchecked: (nothing)
|
||||
|
||||
---
|
||||
|
||||
## HTML5 Input Types
|
||||
|
||||
> **Source:** https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Forms/HTML5_input_types
|
||||
|
||||
HTML5 introduced new `<input type>` values to create native form controls with built-in validation and improved user experience across devices.
|
||||
|
||||
### Email Address Field (`type="email"`)
|
||||
|
||||
```html
|
||||
<label for="email">Enter your email address:</label>
|
||||
<input type="email" id="email" name="email" />
|
||||
```
|
||||
|
||||
**Key Features:**
|
||||
- **Validation**: Browser validates email format before submission
|
||||
- **Multiple emails**: Use `multiple` attribute for comma-separated addresses
|
||||
- **Mobile keyboards**: Displays `@` symbol by default on touch devices
|
||||
- **Invalid state**: Matches `:invalid` pseudo-class and returns `typeMismatch` validity
|
||||
|
||||
```html
|
||||
<input type="email" id="email" name="email" multiple />
|
||||
```
|
||||
|
||||
**Important Notes:**
|
||||
- `a@b` is considered valid (allows intranet addresses)
|
||||
- Use the `pattern` attribute for custom validation
|
||||
|
||||
### Search Field (`type="search"`)
|
||||
|
||||
```html
|
||||
<label for="search">Enter a search term:</label>
|
||||
<input type="search" id="search" name="search" />
|
||||
```
|
||||
|
||||
**Key Features:**
|
||||
- **Visual styling**: Rounded corners in some browsers
|
||||
- **Clear icon**: Displays a clear button to empty the field when focused with a value
|
||||
- **Keyboard**: Enter key may display "search" or magnifying glass icon
|
||||
- **Auto-completion**: Values saved and reused across site pages
|
||||
|
||||
### Phone Number Field (`type="tel"`)
|
||||
|
||||
```html
|
||||
<label for="tel">Enter a telephone number:</label>
|
||||
<input type="tel" id="tel" name="tel" />
|
||||
```
|
||||
|
||||
**Key Features:**
|
||||
- **Mobile keyboards**: Displays numeric keypad on touch devices
|
||||
- **No format enforcement**: Allows letters and special characters (accommodates various international formats)
|
||||
- **Pattern validation**: Use `pattern` attribute to enforce specific formats
|
||||
|
||||
### URL Field (`type="url"`)
|
||||
|
||||
```html
|
||||
<label for="url">Enter a URL:</label>
|
||||
<input type="url" id="url" name="url" />
|
||||
```
|
||||
|
||||
**Key Features:**
|
||||
- **Validation requirements**: Protocol required (e.g., `http:`) and proper URL format enforced
|
||||
- **Mobile keyboards**: Displays colon, period, and forward slash by default
|
||||
- **Note**: Well-formed URLs do not guarantee the site exists
|
||||
|
||||
### Numeric Field (`type="number"`)
|
||||
|
||||
```html
|
||||
<label for="number">Enter a number:</label>
|
||||
<input type="number" id="number" name="number" />
|
||||
```
|
||||
|
||||
**Attributes:**
|
||||
|
||||
| Attribute | Purpose | Example |
|
||||
|-----------|---------|---------|
|
||||
| `min` | Minimum value | `min="1"` |
|
||||
| `max` | Maximum value | `max="10"` |
|
||||
| `step` | Increment/decrement value | `step="2"` |
|
||||
|
||||
**Examples:**
|
||||
|
||||
Odd numbers between 1-10:
|
||||
```html
|
||||
<input type="number" name="age" id="age" min="1" max="10" step="2" />
|
||||
```
|
||||
|
||||
Decimal values (0-1):
|
||||
```html
|
||||
<input type="number" name="change" id="pennies" min="0" max="1" step="0.01" />
|
||||
```
|
||||
|
||||
**Key Features:**
|
||||
- **Spinner buttons**: Increase/decrease values
|
||||
- **Mobile**: Numeric keyboard displayed
|
||||
- **Default step**: `1` (only allows integers unless changed)
|
||||
- **Float numbers**: Use `step="any"` or `step="0.01"`
|
||||
|
||||
### Slider Controls (`type="range"`)
|
||||
|
||||
```html
|
||||
<label for="price">Choose a maximum house price:</label>
|
||||
<input
|
||||
type="range"
|
||||
name="price"
|
||||
id="price"
|
||||
min="50000"
|
||||
max="500000"
|
||||
step="1000"
|
||||
value="250000" />
|
||||
<output class="price-output" for="price"></output>
|
||||
```
|
||||
|
||||
**JavaScript to Display Value:**
|
||||
```javascript
|
||||
const price = document.querySelector("#price");
|
||||
const output = document.querySelector(".price-output");
|
||||
|
||||
output.textContent = price.value;
|
||||
|
||||
price.addEventListener("input", () => {
|
||||
output.textContent = price.value;
|
||||
});
|
||||
```
|
||||
|
||||
**Key Features:**
|
||||
- Less precise than text input (best for approximate values)
|
||||
- Thumb movement via mouse, touch, or keyboard arrows
|
||||
- Use `<output>` element for displaying current value
|
||||
- Configure with `min`, `max`, `step` attributes
|
||||
|
||||
### Date and Time Pickers
|
||||
|
||||
#### Date (`type="date"`)
|
||||
|
||||
```html
|
||||
<label for="date">Enter the date:</label>
|
||||
<input type="date" name="date" id="date" />
|
||||
```
|
||||
Captures: Year, month, day (no time).
|
||||
|
||||
#### Date and Time Local (`type="datetime-local"`)
|
||||
|
||||
```html
|
||||
<label for="datetime">Enter the date and time:</label>
|
||||
<input type="datetime-local" name="datetime" id="datetime" />
|
||||
```
|
||||
Captures: Date and time (no timezone).
|
||||
|
||||
#### Month (`type="month"`)
|
||||
|
||||
```html
|
||||
<label for="month">Enter the month:</label>
|
||||
<input type="month" name="month" id="month" />
|
||||
```
|
||||
Captures: Month and year.
|
||||
|
||||
#### Time (`type="time"`)
|
||||
|
||||
```html
|
||||
<label for="time">Enter a time:</label>
|
||||
<input type="time" name="time" id="time" />
|
||||
```
|
||||
- **Display format**: 12-hour (in some browsers)
|
||||
- **Return format**: Always 24-hour
|
||||
|
||||
#### Week (`type="week"`)
|
||||
|
||||
```html
|
||||
<label for="week">Enter the week:</label>
|
||||
<input type="week" name="week" id="week" />
|
||||
```
|
||||
- Weeks: Monday-Sunday
|
||||
- Week 1: Contains first Thursday of the year
|
||||
|
||||
#### Date/Time Constraints
|
||||
|
||||
```html
|
||||
<label for="myDate">When are you available this summer?</label>
|
||||
<input
|
||||
type="date"
|
||||
name="myDate"
|
||||
min="2025-06-01"
|
||||
max="2025-08-31"
|
||||
step="7"
|
||||
id="myDate" />
|
||||
```
|
||||
|
||||
#### Validation Example (CSS)
|
||||
|
||||
```css
|
||||
input:invalid + span::after {
|
||||
content: " X";
|
||||
}
|
||||
|
||||
input:valid + span::after {
|
||||
content: " checkmark";
|
||||
}
|
||||
```
|
||||
|
||||
### Color Picker (`type="color"`)
|
||||
|
||||
```html
|
||||
<label for="color">Pick a color:</label>
|
||||
<input type="color" name="color" id="color" />
|
||||
```
|
||||
|
||||
**Key Features:**
|
||||
- Opens OS default color-picking functionality
|
||||
- Return value: Always lowercase 6-digit hexadecimal (e.g., `#ff0000`)
|
||||
- No manual format entry: System color picker handles selection
|
||||
|
||||
### Client-Side Validation Notes
|
||||
|
||||
**Advantages:**
|
||||
- Immediate user feedback
|
||||
- Guides accurate form completion
|
||||
- Saves server round trips
|
||||
|
||||
**Important Limitations:**
|
||||
- NOT a security measure -- easily disabled by users
|
||||
- Server-side validation is always required
|
||||
- Prevents only obvious mistakes, not malicious data
|
||||
|
||||
### HTML5 Input Types Summary
|
||||
|
||||
| Type | Purpose | Key Attribute | Mobile Keyboard |
|
||||
|------|---------|---------------|-----------------|
|
||||
| `email` | Email address | `multiple` | @ symbol |
|
||||
| `search` | Search queries | `pattern` | Standard |
|
||||
| `tel` | Phone numbers | `pattern` | Numeric |
|
||||
| `url` | Web URLs | Required protocol | `:/.` symbols |
|
||||
| `number` | Numeric values | `min`, `max`, `step` | Numeric |
|
||||
| `range` | Slider selection | `min`, `max`, `step` | N/A |
|
||||
| `date` | Date picker | `min`, `max` | Calendar |
|
||||
| `time` | Time picker | `min`, `max` | Clock |
|
||||
| `color` | Color picker | Default hex | Color picker |
|
||||
|
||||
---
|
||||
|
||||
## Other Form Controls
|
||||
|
||||
> **Source:** https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Forms/Other_form_controls
|
||||
|
||||
### Multi-Line Text Fields (`<textarea>`)
|
||||
|
||||
```html
|
||||
<textarea cols="30" rows="8"></textarea>
|
||||
```
|
||||
|
||||
**Key Characteristics:**
|
||||
- Allows users to input multiple lines of text
|
||||
- Supports hard line breaks (pressing return)
|
||||
- Content is placed between opening and closing tags
|
||||
- Requires a closing tag (unlike `<input>`)
|
||||
|
||||
**Controlling Multi-Line Rendering:**
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `cols` | Visible width in average character widths (default: 20) |
|
||||
| `rows` | Number of visible text rows (default: 2) |
|
||||
| `wrap` | Text wrapping behavior: `soft` (default), `hard`, or `off` |
|
||||
|
||||
**Example with wrapping:**
|
||||
```html
|
||||
<textarea cols="30" rows="8" wrap="hard"></textarea>
|
||||
```
|
||||
|
||||
**Controlling Resizability (CSS):**
|
||||
```css
|
||||
textarea {
|
||||
resize: both; /* horizontal and vertical */
|
||||
resize: horizontal; /* horizontal only */
|
||||
resize: vertical; /* vertical only */
|
||||
resize: none; /* no resizing */
|
||||
}
|
||||
```
|
||||
|
||||
### Drop-Down Controls
|
||||
|
||||
#### Select Box (Single Selection)
|
||||
|
||||
```html
|
||||
<select id="simple" name="simple">
|
||||
<option>Banana</option>
|
||||
<option selected>Cherry</option>
|
||||
<option>Lemon</option>
|
||||
</select>
|
||||
```
|
||||
|
||||
**With Grouping (`<optgroup>`):**
|
||||
```html
|
||||
<select id="groups" name="groups">
|
||||
<optgroup label="fruits">
|
||||
<option>Banana</option>
|
||||
<option selected>Cherry</option>
|
||||
<option>Lemon</option>
|
||||
</optgroup>
|
||||
<optgroup label="vegetables">
|
||||
<option>Carrot</option>
|
||||
<option>Eggplant</option>
|
||||
<option>Potato</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
```
|
||||
|
||||
**With Value Attributes:**
|
||||
```html
|
||||
<select id="simple" name="simple">
|
||||
<option value="banana">Big, beautiful yellow banana</option>
|
||||
<option value="cherry">Succulent, juicy cherry</option>
|
||||
<option value="lemon">Sharp, powerful lemon</option>
|
||||
</select>
|
||||
```
|
||||
|
||||
**Attributes:**
|
||||
- `selected` -- Sets the default selected option
|
||||
- `value` -- The value sent when form is submitted (if omitted, uses option text)
|
||||
- `size` -- Number of visible options
|
||||
|
||||
#### Multiple Choice Select Box
|
||||
|
||||
```html
|
||||
<select id="multi" name="multi" multiple size="2">
|
||||
<optgroup label="fruits">
|
||||
<option>Banana</option>
|
||||
<option selected>Cherry</option>
|
||||
<option>Lemon</option>
|
||||
</optgroup>
|
||||
<optgroup label="vegetables">
|
||||
<option>Carrot</option>
|
||||
<option>Eggplant</option>
|
||||
<option>Potato</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
- Add `multiple` attribute to allow multiple selections
|
||||
- Users select via Cmd/Ctrl+click on desktop
|
||||
- All values display as a list (not dropdown)
|
||||
|
||||
#### Autocomplete Box (`<datalist>`)
|
||||
|
||||
```html
|
||||
<label for="myFruit">What's your favorite fruit?</label>
|
||||
<input type="text" name="myFruit" id="myFruit" list="mySuggestion" />
|
||||
<datalist id="mySuggestion">
|
||||
<option>Apple</option>
|
||||
<option>Banana</option>
|
||||
<option>Blackberry</option>
|
||||
<option>Blueberry</option>
|
||||
<option>Lemon</option>
|
||||
<option>Lychee</option>
|
||||
<option>Peach</option>
|
||||
<option>Pear</option>
|
||||
</datalist>
|
||||
```
|
||||
|
||||
**How It Works:**
|
||||
- `<datalist>` provides suggested values
|
||||
- Bound to input via `list` attribute (must match datalist `id`)
|
||||
- Browsers display matching values as user types
|
||||
- Works with various input types (text, email, range, color, etc.)
|
||||
|
||||
### Progress Bar (`<progress>`)
|
||||
|
||||
```html
|
||||
<progress max="100" value="75">75/100</progress>
|
||||
```
|
||||
|
||||
**Attributes:**
|
||||
- `max` -- Maximum value (default: 1.0 if not specified)
|
||||
- `value` -- Current progress value
|
||||
- Content inside is fallback for unsupported browsers
|
||||
|
||||
**Use Cases:** Download progress, questionnaire completion, task progress.
|
||||
|
||||
### Meter (`<meter>`)
|
||||
|
||||
```html
|
||||
<meter min="0" max="100" value="75" low="33" high="66" optimum="0">75</meter>
|
||||
```
|
||||
|
||||
**Attributes:**
|
||||
- `min` / `max` -- Range boundaries
|
||||
- `low` / `high` -- Define three ranges (lower, medium, higher)
|
||||
- `value` -- Current meter value
|
||||
- `optimum` -- Preferred value (determines color coding)
|
||||
|
||||
**Color Coding:**
|
||||
- Green: Value in preferred range
|
||||
- Yellow: Value in average range
|
||||
- Red: Value in worst range
|
||||
|
||||
**Optimum Logic:**
|
||||
- If `optimum` in lower range: lower is preferred
|
||||
- If `optimum` in medium range: medium is preferred
|
||||
- If `optimum` in higher range: higher is preferred
|
||||
|
||||
**Use Cases:** Disk space usage, temperature gauge, ratings.
|
||||
|
||||
### Other Form Controls Summary
|
||||
|
||||
| Element | Purpose | Input Type |
|
||||
|---------|---------|------------|
|
||||
| `<textarea>` | Multi-line text input | Text content |
|
||||
| `<select>` | Single or multiple selection | Predefined options |
|
||||
| `<datalist>` | Suggested autocomplete values | Text input with suggestions |
|
||||
| `<progress>` | Progress indication | Read-only display |
|
||||
| `<meter>` | Measurement display | Read-only display |
|
||||
627
skills/create-web-form/references/form-data-handling.md
Normal file
627
skills/create-web-form/references/form-data-handling.md
Normal file
@@ -0,0 +1,627 @@
|
||||
# Form Data Handling Reference
|
||||
|
||||
---
|
||||
|
||||
## Section 1: Sending and Retrieving Form Data
|
||||
|
||||
**Source:** https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Forms/Sending_and_retrieving_form_data
|
||||
|
||||
### Overview
|
||||
|
||||
Once form data is validated on the client-side, it is ready to submit. This section covers what happens when a user submits a form, where the data goes, and how to handle it on the server.
|
||||
|
||||
### Client/Server Architecture
|
||||
|
||||
The web uses a basic client/server architecture:
|
||||
|
||||
- **Client** (web browser) sends an HTTP request to a **server**.
|
||||
- **Server** (Apache, Nginx, IIS, Tomcat) responds using the same protocol.
|
||||
- HTML forms are a user-friendly way to configure HTTP requests for sending data.
|
||||
|
||||
### On the Client Side: Defining How to Send Data
|
||||
|
||||
The `<form>` element controls how data is sent. Two critical attributes are `action` and `method`.
|
||||
|
||||
#### The `action` Attribute
|
||||
|
||||
The `action` attribute defines where form data gets sent. It must be a valid relative or absolute URL.
|
||||
|
||||
**Absolute URL:**
|
||||
|
||||
```html
|
||||
<form action="https://www.example.com">...</form>
|
||||
```
|
||||
|
||||
**Relative URL (same origin):**
|
||||
|
||||
```html
|
||||
<form action="/somewhere_else">...</form>
|
||||
```
|
||||
|
||||
**Same page (no attributes or empty action):**
|
||||
|
||||
```html
|
||||
<form>...</form>
|
||||
```
|
||||
|
||||
**Security Note:** Use HTTPS (secure HTTP) to encrypt data. If a secure form posts to an insecure HTTP URL, browsers display a security warning.
|
||||
|
||||
#### The `method` Attribute
|
||||
|
||||
Two main HTTP methods transmit form data: **GET** and **POST**.
|
||||
|
||||
### GET Method
|
||||
|
||||
- Used by browsers to ask the server to send back a resource.
|
||||
- Data is appended to the URL as query parameters.
|
||||
- Browser sends an empty body.
|
||||
|
||||
**Example Form:**
|
||||
|
||||
```html
|
||||
<form action="https://www.example.com/greet" method="GET">
|
||||
<div>
|
||||
<label for="say">What greeting do you want to say?</label>
|
||||
<input name="say" id="say" value="Hi" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="to">Who do you want to say it to?</label>
|
||||
<input name="to" id="to" value="Mom" />
|
||||
</div>
|
||||
<div>
|
||||
<button>Send my greetings</button>
|
||||
</div>
|
||||
</form>
|
||||
```
|
||||
|
||||
**Result URL:** `https://www.example.com/greet?say=Hi&to=Mom`
|
||||
|
||||
**HTTP Request:**
|
||||
|
||||
```http
|
||||
GET /?say=Hi&to=Mom HTTP/2.0
|
||||
Host: example.com
|
||||
```
|
||||
|
||||
**When to use:** Reading data, non-sensitive information.
|
||||
|
||||
### POST Method
|
||||
|
||||
- Used to send data that the server should process.
|
||||
- Data is included in the HTTP request body, not the URL.
|
||||
- More secure for sensitive data (passwords, etc.).
|
||||
|
||||
**Example Form:**
|
||||
|
||||
```html
|
||||
<form action="https://www.example.com/greet" method="POST">
|
||||
<div>
|
||||
<label for="say">What greeting do you want to say?</label>
|
||||
<input name="say" id="say" value="Hi" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="to">Who do you want to say it to?</label>
|
||||
<input name="to" id="to" value="Mom" />
|
||||
</div>
|
||||
<div>
|
||||
<button>Send my greetings</button>
|
||||
</div>
|
||||
</form>
|
||||
```
|
||||
|
||||
**HTTP Request:**
|
||||
|
||||
```http
|
||||
POST / HTTP/2.0
|
||||
Host: example.com
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Content-Length: 13
|
||||
|
||||
say=Hi&to=Mom
|
||||
```
|
||||
|
||||
**When to use:** Sensitive data, large amounts of data, modifying server state.
|
||||
|
||||
### Viewing HTTP Requests in Browser DevTools
|
||||
|
||||
1. Open Developer Tools (F12).
|
||||
2. Select the "Network" tab.
|
||||
3. Select "All" to see all requests.
|
||||
4. Click the request in the "Name" tab.
|
||||
5. View "Request" (Firefox) or "Payload" (Chrome/Edge).
|
||||
|
||||
### On the Server Side: Retrieving the Data
|
||||
|
||||
The server receives data as a string parsed into key/value pairs. Access method depends on the server platform.
|
||||
|
||||
#### Example: Raw PHP
|
||||
|
||||
```php
|
||||
<?php
|
||||
// Access POST data
|
||||
$say = htmlspecialchars($_POST["say"]);
|
||||
$to = htmlspecialchars($_POST["to"]);
|
||||
|
||||
// Access GET data
|
||||
// $say = htmlspecialchars($_GET["say"]);
|
||||
|
||||
echo $say, " ", $to;
|
||||
?>
|
||||
```
|
||||
|
||||
**Output:** `Hi Mom`
|
||||
|
||||
#### Example: Python with Flask
|
||||
|
||||
```python
|
||||
from flask import Flask, render_template, request
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route('/', methods=['GET', 'POST'])
|
||||
def form():
|
||||
return render_template('form.html')
|
||||
|
||||
@app.route('/hello', methods=['GET', 'POST'])
|
||||
def hello():
|
||||
return render_template('greeting.html',
|
||||
say=request.form['say'],
|
||||
to=request.form['to'])
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run()
|
||||
```
|
||||
|
||||
#### Other Server-Side Frameworks
|
||||
|
||||
| Language | Frameworks |
|
||||
|------------|-----------------------------------------|
|
||||
| Python | Django, Flask, web2py, py4web |
|
||||
| Node.js | Express, Next.js, Nuxt, Remix |
|
||||
| PHP | Laravel, Laminas, Symfony |
|
||||
| Ruby | Ruby On Rails |
|
||||
| Java | Spring Boot |
|
||||
|
||||
### A Special Case: Sending Files
|
||||
|
||||
Files are binary data and require special handling. Three steps are needed:
|
||||
|
||||
#### The `enctype` Attribute
|
||||
|
||||
This specifies the `Content-Type` HTTP header.
|
||||
|
||||
- **Default:** `application/x-www-form-urlencoded`
|
||||
- **For files:** `multipart/form-data`
|
||||
|
||||
**File Upload Example:**
|
||||
|
||||
```html
|
||||
<form
|
||||
method="post"
|
||||
action="https://example.com/upload"
|
||||
enctype="multipart/form-data">
|
||||
<div>
|
||||
<label for="file">Choose a file</label>
|
||||
<input type="file" id="file" name="myFile" />
|
||||
</div>
|
||||
<div>
|
||||
<button>Send the file</button>
|
||||
</div>
|
||||
</form>
|
||||
```
|
||||
|
||||
**Requirements:**
|
||||
|
||||
- Set `method` to `POST` (file content cannot go in a URL).
|
||||
- Set `enctype` to `multipart/form-data`.
|
||||
- Include one or more `<input type="file">` controls.
|
||||
|
||||
**Note:** Servers can limit file and request sizes to prevent abuse.
|
||||
|
||||
### Security Considerations
|
||||
|
||||
#### Be Paranoid: Never Trust Your Users
|
||||
|
||||
All incoming data must be checked and sanitized:
|
||||
|
||||
1. **Escape Dangerous Characters** -- Watch for executable code patterns (JavaScript, SQL commands). Use server-side escaping functions. Different contexts require different escaping.
|
||||
2. **Limit Incoming Data** -- Only accept what is necessary. Set maximum sizes for requests.
|
||||
3. **Sandbox Uploaded Files** -- Store on a different server. Serve through a different subdomain or domain. Never execute uploaded files directly.
|
||||
|
||||
**Key Rule:** Never trust client-side validation alone -- always validate on the server. Client-side validation can be bypassed; the server has no way to verify what truly happened on the client.
|
||||
|
||||
### Quick Reference: GET vs POST
|
||||
|
||||
| Aspect | GET | POST |
|
||||
|--------------------|--------------------------------------|----------------------------------------|
|
||||
| Data location | Visible in URL as query parameters | Hidden in request body |
|
||||
| Data size | Limited by URL length | No inherent limit |
|
||||
| Security | Not suitable for sensitive data | Better for sensitive/large data |
|
||||
| Caching | Can be cached | Not cached |
|
||||
| Use case | Reading/retrieving data | Modifying server state, sending files |
|
||||
|
||||
### Important Notes
|
||||
|
||||
- **Form data format:** Name/value pairs joined with ampersands (`name=value&name2=value2`).
|
||||
- **URL encoding:** Special characters are URL-encoded in query parameters.
|
||||
- **Default form target:** Without `action`, data submits to the current page.
|
||||
- **Secure protocol:** Always use HTTPS for sensitive data.
|
||||
|
||||
---
|
||||
|
||||
## Section 2: Form Validation
|
||||
|
||||
**Source:** https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Forms/Form_validation
|
||||
|
||||
### Overview
|
||||
|
||||
Client-side form validation helps ensure data entered matches requirements set by form controls. While important for **user experience**, it must **always** be paired with server-side validation since client-side validation is easily bypassed by malicious users.
|
||||
|
||||
### Built-In HTML Validation Attributes
|
||||
|
||||
#### `required`
|
||||
|
||||
Specifies that a form field must be filled before submission.
|
||||
|
||||
```html
|
||||
<input id="choose" name="i-like" required />
|
||||
```
|
||||
|
||||
- Input matches `:required` and `:invalid` pseudo-classes when empty.
|
||||
- For radio buttons, one button in a same-named group must be checked.
|
||||
|
||||
#### `minlength` and `maxlength`
|
||||
|
||||
Constrains character length for text fields and textareas.
|
||||
|
||||
```html
|
||||
<input type="text" minlength="6" maxlength="6" />
|
||||
<textarea maxlength="140"></textarea>
|
||||
```
|
||||
|
||||
#### `min`, `max`, and `step`
|
||||
|
||||
Constrains numeric values and their increments.
|
||||
|
||||
```html
|
||||
<input type="number" min="1" max="10" step="1" />
|
||||
<input type="date" min="2024-01-01" max="2024-12-31" />
|
||||
```
|
||||
|
||||
#### `type`
|
||||
|
||||
Validates against specific formats (email, URL, number, date, etc.).
|
||||
|
||||
```html
|
||||
<input type="email" />
|
||||
<input type="url" />
|
||||
<input type="number" />
|
||||
```
|
||||
|
||||
#### `pattern`
|
||||
|
||||
Validates against a regular expression.
|
||||
|
||||
```html
|
||||
<input
|
||||
type="text"
|
||||
pattern="[Bb]anana|[Cc]herry"
|
||||
required
|
||||
/>
|
||||
```
|
||||
|
||||
**Pattern Examples:**
|
||||
|
||||
| Pattern | Matches |
|
||||
|----------|------------------------------------------|
|
||||
| `a` | Single character 'a' |
|
||||
| `abc` | 'a' followed by 'b' followed by 'c' |
|
||||
| `ab?c` | 'ac' or 'abc' |
|
||||
| `ab*c` | 'ac', 'abc', 'abbbbbc', etc. |
|
||||
| `a\|b` | 'a' or 'b' |
|
||||
|
||||
### CSS Pseudo-Classes for Validation States
|
||||
|
||||
#### Valid States
|
||||
|
||||
```css
|
||||
input:valid {
|
||||
border: 2px solid black;
|
||||
}
|
||||
|
||||
input:user-valid {
|
||||
/* Matches after user interaction */
|
||||
}
|
||||
|
||||
input:in-range {
|
||||
/* For inputs with min/max */
|
||||
}
|
||||
```
|
||||
|
||||
#### Invalid States
|
||||
|
||||
```css
|
||||
input:invalid {
|
||||
border: 2px dashed red;
|
||||
}
|
||||
|
||||
input:user-invalid {
|
||||
/* Matches after user interaction */
|
||||
}
|
||||
|
||||
input:out-of-range {
|
||||
/* For inputs with min/max */
|
||||
}
|
||||
|
||||
input:required {
|
||||
/* Matches required fields */
|
||||
}
|
||||
```
|
||||
|
||||
### Complete Built-In Validation Example
|
||||
|
||||
```html
|
||||
<form>
|
||||
<p>Please complete all required (*) fields.</p>
|
||||
|
||||
<fieldset>
|
||||
<legend>Do you have a driver's license? *</legend>
|
||||
<input type="radio" required name="driver" id="r1" value="yes" />
|
||||
<label for="r1">Yes</label>
|
||||
<input type="radio" required name="driver" id="r2" value="no" />
|
||||
<label for="r2">No</label>
|
||||
</fieldset>
|
||||
|
||||
<p>
|
||||
<label for="age">How old are you?</label>
|
||||
<input type="number" min="12" max="120" step="1" id="age" name="age" />
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="fruit">What's your favorite fruit? *</label>
|
||||
<input
|
||||
type="text"
|
||||
id="fruit"
|
||||
name="fruit"
|
||||
list="fruits"
|
||||
required
|
||||
pattern="[Bb]anana|[Cc]herry|[Aa]pple"
|
||||
/>
|
||||
<datalist id="fruits">
|
||||
<option>Banana</option>
|
||||
<option>Cherry</option>
|
||||
<option>Apple</option>
|
||||
</datalist>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="email">Email address:</label>
|
||||
<input type="email" id="email" name="email" />
|
||||
</p>
|
||||
|
||||
<button>Submit</button>
|
||||
</form>
|
||||
```
|
||||
|
||||
### Constraint Validation API
|
||||
|
||||
The Constraint Validation API provides methods and properties for custom validation logic.
|
||||
|
||||
#### Key Properties
|
||||
|
||||
**`validationMessage`** -- Returns localized validation error message.
|
||||
|
||||
**`validity`** -- Returns a `ValidityState` object with these properties:
|
||||
|
||||
| Property | Description |
|
||||
|-------------------|-----------------------------------------------------|
|
||||
| `valid` | `true` if element meets all constraints |
|
||||
| `valueMissing` | `true` if required but empty |
|
||||
| `typeMismatch` | `true` if value does not match type (e.g., email) |
|
||||
| `patternMismatch` | `true` if pattern does not match |
|
||||
| `tooLong` | `true` if exceeds `maxlength` |
|
||||
| `tooShort` | `true` if below `minlength` |
|
||||
| `rangeOverflow` | `true` if exceeds `max` |
|
||||
| `rangeUnderflow` | `true` if below `min` |
|
||||
| `customError` | `true` if custom error set via `setCustomValidity()` |
|
||||
|
||||
**`willValidate`** -- Boolean, `true` if element will be validated on form submission.
|
||||
|
||||
#### Key Methods
|
||||
|
||||
```javascript
|
||||
// Check validity without submitting
|
||||
element.checkValidity() // Returns boolean
|
||||
|
||||
// Report validity to user
|
||||
element.reportValidity() // Shows browser's error message
|
||||
|
||||
// Set custom error message
|
||||
element.setCustomValidity("Custom error text")
|
||||
|
||||
// Clear custom error
|
||||
element.setCustomValidity("")
|
||||
```
|
||||
|
||||
### JavaScript Custom Validation Examples
|
||||
|
||||
#### Basic Custom Error Message
|
||||
|
||||
```javascript
|
||||
const email = document.getElementById("mail");
|
||||
|
||||
email.addEventListener("input", (event) => {
|
||||
if (email.validity.typeMismatch) {
|
||||
email.setCustomValidity("I am expecting an email address!");
|
||||
} else {
|
||||
email.setCustomValidity("");
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### Extending Built-In Validation
|
||||
|
||||
```javascript
|
||||
const email = document.getElementById("mail");
|
||||
|
||||
email.addEventListener("input", (event) => {
|
||||
// Reset custom validity
|
||||
email.setCustomValidity("");
|
||||
|
||||
// Check built-in constraints first
|
||||
if (!email.validity.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add custom constraint
|
||||
if (!email.value.endsWith("@example.com")) {
|
||||
email.setCustomValidity("Please enter an email with @example.com domain");
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### Complex Form Validation with Custom Messages
|
||||
|
||||
```javascript
|
||||
const form = document.querySelector("form");
|
||||
const email = document.getElementById("mail");
|
||||
const emailError = document.querySelector("#mail + span.error");
|
||||
|
||||
email.addEventListener("input", (event) => {
|
||||
if (email.validity.valid) {
|
||||
emailError.textContent = "";
|
||||
emailError.className = "error";
|
||||
} else {
|
||||
showError();
|
||||
}
|
||||
});
|
||||
|
||||
form.addEventListener("submit", (event) => {
|
||||
if (!email.validity.valid) {
|
||||
showError();
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
function showError() {
|
||||
if (email.validity.valueMissing) {
|
||||
emailError.textContent = "You need to enter an email address.";
|
||||
} else if (email.validity.typeMismatch) {
|
||||
emailError.textContent = "Entered value needs to be an email address.";
|
||||
} else if (email.validity.tooShort) {
|
||||
emailError.textContent =
|
||||
`Email should be at least ${email.minLength} characters; you entered ${email.value.length}.`;
|
||||
}
|
||||
emailError.className = "error active";
|
||||
}
|
||||
```
|
||||
|
||||
#### Disabling Built-In Validation with `novalidate`
|
||||
|
||||
Use `novalidate` on the form to disable the browser's automatic validation while retaining CSS pseudo-classes:
|
||||
|
||||
```html
|
||||
<form novalidate>
|
||||
<input type="email" id="mail" required minlength="8" />
|
||||
<span class="error" aria-live="polite"></span>
|
||||
</form>
|
||||
```
|
||||
|
||||
### Manual Validation Without the Constraint API
|
||||
|
||||
For custom form controls or complete control over validation:
|
||||
|
||||
```javascript
|
||||
const form = document.querySelector("form");
|
||||
const email = document.getElementById("mail");
|
||||
const error = document.getElementById("error");
|
||||
|
||||
const emailRegExp = /^[\w.!#$%&'*+/=?^`{|}~-]+@[a-z\d-]+(?:\.[a-z\d-]+)*$/i;
|
||||
|
||||
const isValidEmail = () => {
|
||||
return email.value.length !== 0 && emailRegExp.test(email.value);
|
||||
};
|
||||
|
||||
const setEmailClass = (isValid) => {
|
||||
email.className = isValid ? "valid" : "invalid";
|
||||
};
|
||||
|
||||
const updateError = (isValid) => {
|
||||
if (isValid) {
|
||||
error.textContent = "";
|
||||
error.removeAttribute("class");
|
||||
} else {
|
||||
error.textContent = "Please enter a valid email address.";
|
||||
error.setAttribute("class", "active");
|
||||
}
|
||||
};
|
||||
|
||||
email.addEventListener("input", () => {
|
||||
const validity = isValidEmail();
|
||||
setEmailClass(validity);
|
||||
updateError(validity);
|
||||
});
|
||||
|
||||
form.addEventListener("submit", (event) => {
|
||||
event.preventDefault();
|
||||
const validity = isValidEmail();
|
||||
setEmailClass(validity);
|
||||
updateError(validity);
|
||||
});
|
||||
```
|
||||
|
||||
### Styling Error Messages
|
||||
|
||||
```css
|
||||
/* Invalid field styling */
|
||||
input:invalid {
|
||||
border-color: #990000;
|
||||
background-color: #ffdddd;
|
||||
}
|
||||
|
||||
input:focus:invalid {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Error message container */
|
||||
.error {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
font-size: 80%;
|
||||
color: white;
|
||||
background-color: #990000;
|
||||
border-radius: 0 0 5px 5px;
|
||||
}
|
||||
|
||||
.error.active {
|
||||
padding: 0.3em;
|
||||
}
|
||||
```
|
||||
|
||||
### Accessibility Best Practices
|
||||
|
||||
1. **Mark required fields** with an asterisk in the label:
|
||||
```html
|
||||
<label for="name">Name *</label>
|
||||
```
|
||||
2. **Use `aria-live`** for dynamic error messages:
|
||||
```html
|
||||
<span class="error" aria-live="polite"></span>
|
||||
```
|
||||
3. **Provide clear, helpful messages** that explain what is expected and how to fix errors.
|
||||
4. **Avoid relying on color alone** to indicate errors.
|
||||
|
||||
### Validation Summary
|
||||
|
||||
| Approach | Pros | Cons |
|
||||
|------------------------|---------------------------------------------|----------------------------------------|
|
||||
| HTML built-in | No JavaScript needed, fast | Limited customization |
|
||||
| Constraint Validation API | Modern, integrates with built-in features | Requires JavaScript |
|
||||
| Fully manual (JS) | Complete control over UI and logic | More code, must handle everything |
|
||||
|
||||
- **HTML validation** is faster and does not require JavaScript.
|
||||
- **JavaScript validation** provides more customization and control.
|
||||
- **Always validate server-side** -- client-side validation is not secure.
|
||||
- **Use the Constraint Validation API** for modern, built-in functionality.
|
||||
- **Provide clear error messages** and guidance to users.
|
||||
- **Style validation states** with `:valid` and `:invalid` pseudo-classes.
|
||||
822
skills/create-web-form/references/html-form-elements.md
Normal file
822
skills/create-web-form/references/html-form-elements.md
Normal file
@@ -0,0 +1,822 @@
|
||||
# HTML Form Elements Reference
|
||||
|
||||
A consolidated reference for HTML form-related elements, sourced from the Mozilla Developer Network (MDN) Web Docs.
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [`<form>`](#form)
|
||||
2. [`HTMLFormElement.elements`](#htmlformelementelements)
|
||||
3. [`<button>`](#button)
|
||||
4. [`<datalist>`](#datalist)
|
||||
5. [`<fieldset>`](#fieldset)
|
||||
6. [`<input>`](#input)
|
||||
7. [`<label>`](#label)
|
||||
8. [`<legend>`](#legend)
|
||||
9. [`<meter>`](#meter)
|
||||
10. [`<optgroup>`](#optgroup)
|
||||
11. [`<option>`](#option)
|
||||
12. [`<output>`](#output)
|
||||
13. [`<progress>`](#progress)
|
||||
14. [`<select>`](#select)
|
||||
15. [`<textarea>`](#textarea)
|
||||
|
||||
---
|
||||
|
||||
## `<form>`
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/form>
|
||||
|
||||
### Description
|
||||
|
||||
The `<form>` element represents a document section containing interactive controls for submitting information to a server. Both opening and closing tags are mandatory. Forms cannot be nested inside other forms.
|
||||
|
||||
### Key Attributes
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `action` | URL that processes the form submission. Can be overridden by `formaction` on submit buttons. |
|
||||
| `method` | HTTP method: `get` (default), `post`, or `dialog`. Defines how data is sent. |
|
||||
| `enctype` | MIME type for POST submissions: `application/x-www-form-urlencoded` (default), `multipart/form-data` (for files), `text/plain`. |
|
||||
| `novalidate` | Boolean attribute that disables form validation on submission. |
|
||||
| `autocomplete` | Controls auto-completion: `on` (default) or `off`. |
|
||||
| `accept-charset` | Character encoding accepted (typically `UTF-8`). |
|
||||
| `name` | Form identifier; must be unique. Becomes a property of `window`, `document`, and `document.forms`. |
|
||||
| `target` | Where to display the response: `_self` (default), `_blank`, `_parent`, `_top`. |
|
||||
| `rel` | Link relationship types: `external`, `nofollow`, `noopener`, `noreferrer`, etc. |
|
||||
|
||||
### Usage Notes
|
||||
|
||||
- Forms **cannot contain nested forms**.
|
||||
- Supports CSS pseudo-classes: `:valid` and `:invalid` for styling based on form validity.
|
||||
- DOM Interface: `HTMLFormElement`.
|
||||
- Implicit ARIA role: `form`.
|
||||
|
||||
### Example
|
||||
|
||||
```html
|
||||
<form action="/submit" method="post">
|
||||
<div>
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" id="name" name="name" required />
|
||||
</div>
|
||||
<div>
|
||||
<label for="email">Email:</label>
|
||||
<input type="email" id="email" name="email" required />
|
||||
</div>
|
||||
<input type="submit" value="Submit" />
|
||||
</form>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `HTMLFormElement.elements`
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements>
|
||||
|
||||
### Description
|
||||
|
||||
The `elements` property returns an `HTMLFormControlsCollection` containing all the form controls associated with a `<form>` element. Controls can be accessed by index or by their `name`/`id` attributes.
|
||||
|
||||
### Return Value
|
||||
|
||||
- **Type:** `HTMLFormControlsCollection` (a live collection based on `HTMLCollection`)
|
||||
- **Live:** Yes -- automatically updates when controls are added or removed.
|
||||
- **Order:** Tree order (preorder, depth-first traversal of the document).
|
||||
|
||||
### Included Form Controls
|
||||
|
||||
The collection includes:
|
||||
|
||||
- `<button>`
|
||||
- `<fieldset>`
|
||||
- `<input>` (except `type="image"`)
|
||||
- `<object>`
|
||||
- `<output>`
|
||||
- `<select>`
|
||||
- `<textarea>`
|
||||
- Form-associated custom elements
|
||||
|
||||
**Note:** `<label>` and `<legend>` elements are **not** included.
|
||||
|
||||
### Example
|
||||
|
||||
```javascript
|
||||
// Access form controls
|
||||
const inputs = document.getElementById("my-form").elements;
|
||||
const firstControl = inputs[0]; // By index
|
||||
const byName = inputs["username"]; // By name attribute
|
||||
|
||||
// Iterate over controls
|
||||
for (const control of inputs) {
|
||||
if (control.nodeName === "INPUT" && control.type === "text") {
|
||||
control.value = control.value.toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
// Get number of controls
|
||||
console.log(inputs.length);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `<button>`
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/button>
|
||||
|
||||
### Description
|
||||
|
||||
The `<button>` element is an interactive element activated by a user (via mouse, keyboard, finger, voice, or assistive technology) that performs an action, such as submitting a form or opening a dialog. By default, its appearance reflects the user's platform but can be fully customized with CSS.
|
||||
|
||||
### Key Attributes
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `type` | Specifies behavior: `submit` (default for forms), `reset` (clears form), `button` (no default behavior). |
|
||||
| `disabled` | Boolean; prevents user interaction. |
|
||||
| `name` | Button name for form submission. |
|
||||
| `value` | Value submitted with form data. |
|
||||
| `form` | Associates button with a form by ID. |
|
||||
| `formaction` | Overrides form's `action` URL. |
|
||||
| `formmethod` | Overrides form's HTTP method (`post`/`get`). |
|
||||
| `autofocus` | Gives button focus on page load. |
|
||||
| `popovertarget` | Controls a popover element by ID. |
|
||||
| `popovertargetaction` | Popover action: `show`, `hide`, or `toggle`. |
|
||||
|
||||
### Usage Notes
|
||||
|
||||
- `<button>` is easier to style than `<input type="button">` because it supports inner HTML content (text, images, icons, pseudo-elements).
|
||||
- Always set `type="button"` for non-form buttons to prevent unintended form submission.
|
||||
- Default display is `flow-root`; buttons center children both horizontally and vertically.
|
||||
|
||||
### Accessibility Considerations
|
||||
|
||||
- Icon-only buttons must include visible text or ARIA attributes describing functionality.
|
||||
- Minimum recommended interactive target size: 44x44 CSS pixels.
|
||||
- Space buttons adequately to prevent accidental activation.
|
||||
- Use `:focus-visible` for keyboard focus indicators with sufficient contrast (4.5:1 ratio).
|
||||
- Use `aria-pressed` to describe toggle button state (not `aria-checked` or `aria-selected`).
|
||||
|
||||
### Example
|
||||
|
||||
```html
|
||||
<!-- Basic button -->
|
||||
<button type="button">Click me</button>
|
||||
|
||||
<!-- Form submission button -->
|
||||
<form>
|
||||
<input type="text" name="username" />
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
|
||||
<!-- Styled button -->
|
||||
<button class="favorite" type="button">Add to favorites</button>
|
||||
|
||||
<style>
|
||||
.favorite {
|
||||
padding: 10px 20px;
|
||||
background-color: tomato;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.favorite:hover {
|
||||
background-color: red;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `<datalist>`
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/datalist>
|
||||
|
||||
### Description
|
||||
|
||||
The `<datalist>` element contains a set of `<option>` elements that represent permissible or recommended options available to choose from within other controls, such as `<input>` elements. It provides autocomplete/suggestion functionality without restricting user input.
|
||||
|
||||
### How It Works
|
||||
|
||||
The `<datalist>` is associated with an `<input>` element via:
|
||||
|
||||
1. Give the `<datalist>` a unique `id`.
|
||||
2. Add the `list` attribute to the `<input>` with the same `id` value.
|
||||
|
||||
### Key Attributes
|
||||
|
||||
- **`<datalist>` itself:** No specific attributes (only global attributes like `id`).
|
||||
- **`<option>` children:** `value` (the suggestion; required), `label` (display text; optional).
|
||||
|
||||
### Supported Input Types
|
||||
|
||||
- Text-based: `text`, `search`, `url`, `tel`, `email`, `number`
|
||||
- Date/Time: `month`, `week`, `date`, `time`, `datetime-local`
|
||||
- Visual: `range`, `color`
|
||||
|
||||
### Usage Notes
|
||||
|
||||
- **Not a replacement for `<select>`** -- users can still enter values not in the list.
|
||||
- Provides suggestions, not restrictions.
|
||||
- Browser styling of the dropdown is limited.
|
||||
- Some screen readers may not announce suggestions.
|
||||
|
||||
### Example
|
||||
|
||||
```html
|
||||
<label for="ice-cream-choice">Choose a flavor:</label>
|
||||
<input list="ice-cream-flavors" id="ice-cream-choice" />
|
||||
|
||||
<datalist id="ice-cream-flavors">
|
||||
<option value="Chocolate"></option>
|
||||
<option value="Coconut"></option>
|
||||
<option value="Mint"></option>
|
||||
<option value="Strawberry"></option>
|
||||
<option value="Vanilla"></option>
|
||||
</datalist>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `<fieldset>`
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/fieldset>
|
||||
|
||||
### Description
|
||||
|
||||
The `<fieldset>` element is used to group several form controls and labels together within a web form. It provides semantic grouping and visual organization of related form fields.
|
||||
|
||||
### Key Attributes
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `disabled` | Boolean attribute that disables all form controls inside the fieldset (except those in `<legend>`). Disabled controls will not be editable or submitted. |
|
||||
| `form` | Links the fieldset to a `<form>` by referencing the form's `id`, even if the fieldset is not nested inside it. |
|
||||
| `name` | Specifies the name associated with the group. |
|
||||
|
||||
### Usage Notes
|
||||
|
||||
- The first `<legend>` element nested in the fieldset provides its caption and should be the first child.
|
||||
- Displays as `block` by default with a 2px groove border and padding.
|
||||
- When disabled, all descendant form controls become disabled *except* those inside the `<legend>` element.
|
||||
- Implicit ARIA role: `group`.
|
||||
- DOM Interface: `HTMLFieldSetElement`.
|
||||
|
||||
### Example
|
||||
|
||||
```html
|
||||
<form>
|
||||
<fieldset>
|
||||
<legend>Choose your favorite monster</legend>
|
||||
|
||||
<input type="radio" id="kraken" name="monster" value="K" />
|
||||
<label for="kraken">Kraken</label><br />
|
||||
|
||||
<input type="radio" id="sasquatch" name="monster" value="S" />
|
||||
<label for="sasquatch">Sasquatch</label><br />
|
||||
|
||||
<input type="radio" id="mothman" name="monster" value="M" />
|
||||
<label for="mothman">Mothman</label>
|
||||
</fieldset>
|
||||
</form>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `<input>`
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input>
|
||||
|
||||
### Description
|
||||
|
||||
The `<input>` element creates interactive controls for web-based forms to accept data from the user. It is one of the most powerful and complex HTML elements due to the numerous combinations of input types and attributes.
|
||||
|
||||
### Input Types (24 total)
|
||||
|
||||
| Type | Purpose |
|
||||
|------|---------|
|
||||
| `button` | Push button with no default behavior |
|
||||
| `checkbox` | Single value selection/deselection |
|
||||
| `color` | Color picker control |
|
||||
| `date` | Date input (year, month, day) |
|
||||
| `datetime-local` | Date and time without timezone |
|
||||
| `email` | Email address field |
|
||||
| `file` | File upload control |
|
||||
| `hidden` | Non-displayed value submitted to server |
|
||||
| `image` | Graphical submit button |
|
||||
| `month` | Month and year input |
|
||||
| `number` | Numeric input with validation |
|
||||
| `password` | Obscured text field |
|
||||
| `radio` | Single choice from multiple options |
|
||||
| `range` | Numeric value selector (slider) |
|
||||
| `reset` | Form reset button |
|
||||
| `search` | Search string input |
|
||||
| `submit` | Form submission button |
|
||||
| `tel` | Telephone number field |
|
||||
| `text` | Single-line text (default) |
|
||||
| `time` | Time input |
|
||||
| `url` | URL field with validation |
|
||||
| `week` | Week and year input |
|
||||
|
||||
### Key Attributes
|
||||
|
||||
| Attribute | Applicable Types | Purpose |
|
||||
|-----------|-----------------|---------|
|
||||
| `type` | All | Specifies the input control type |
|
||||
| `name` | All | Form control identifier for submission |
|
||||
| `value` | All | Control's initial/current value |
|
||||
| `id` | All | Unique element identifier |
|
||||
| `required` | Most | Makes input mandatory |
|
||||
| `disabled` | All | Disables user interaction |
|
||||
| `readonly` | Text-like | Prevents value editing |
|
||||
| `placeholder` | Text-like | Hint text when empty |
|
||||
| `min` / `max` | Numeric/date | Value range limits |
|
||||
| `minlength` / `maxlength` | Text-like | Character count limits |
|
||||
| `pattern` | Text-like | Regex validation pattern |
|
||||
| `step` | Numeric/date | Incremental value steps |
|
||||
| `autocomplete` | Most | Form autofill hint |
|
||||
| `list` | Most | Associates with `<datalist>` |
|
||||
| `checked` | Checkbox/radio | Pre-selected state |
|
||||
| `multiple` | Email/file | Allow multiple values |
|
||||
|
||||
### Usage Notes
|
||||
|
||||
- **Labels required:** Always pair inputs with `<label>` elements for accessibility.
|
||||
- **Placeholders are not labels:** Placeholders disappear when typing and are not accessible to all screen readers.
|
||||
- **Client-side validation:** Use constraint attributes (`required`, `pattern`, `min`, `max`) for browser validation, but always validate server-side as well.
|
||||
- **Default type:** If `type` is not specified, it defaults to `text`.
|
||||
- **Form association:** Use `name` attribute for form submission; inputs without `name` are not submitted.
|
||||
- **CSS pseudo-classes:** Style with `:invalid`, `:valid`, `:checked`, `:disabled`, `:placeholder-shown`, etc.
|
||||
|
||||
### Example
|
||||
|
||||
```html
|
||||
<label for="name">Name (4 to 8 characters):</label>
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
name="name"
|
||||
required
|
||||
minlength="4"
|
||||
maxlength="8"
|
||||
size="10" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `<label>`
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/label>
|
||||
|
||||
### Description
|
||||
|
||||
The `<label>` element represents a caption for an item in a user interface. It associates descriptive text with form controls to enhance usability and accessibility.
|
||||
|
||||
### Key Attributes
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `for` | The `id` of the labelable form control to associate with this label. JavaScript reflection: `htmlFor`. |
|
||||
|
||||
### Associating Labels with Controls
|
||||
|
||||
**Explicit association (recommended):**
|
||||
|
||||
```html
|
||||
<label for="username">Enter your username:</label>
|
||||
<input id="username" name="username" type="text" />
|
||||
```
|
||||
|
||||
**Implicit association:**
|
||||
|
||||
```html
|
||||
<label>
|
||||
I like peas.
|
||||
<input type="checkbox" name="peas" />
|
||||
</label>
|
||||
```
|
||||
|
||||
**Combined (both methods for maximum compatibility):**
|
||||
|
||||
```html
|
||||
<label for="peas">
|
||||
I like peas.
|
||||
<input type="checkbox" name="peas" id="peas" />
|
||||
</label>
|
||||
```
|
||||
|
||||
### Labelable Elements
|
||||
|
||||
Labels can be associated with: `<button>`, `<input>` (except `type="hidden"`), `<meter>`, `<output>`, `<progress>`, `<select>`, and `<textarea>`.
|
||||
|
||||
### Accessibility Guidelines
|
||||
|
||||
**Do:**
|
||||
- Use explicit association with the `for` attribute for broad tool compatibility.
|
||||
- Place context (like links to terms) *before* the form control.
|
||||
- Use `<legend>` within `<fieldset>` for form section titles.
|
||||
|
||||
**Do not:**
|
||||
- Place interactive elements (links, buttons) inside labels -- it makes form controls difficult to activate.
|
||||
- Use heading elements inside labels -- it interferes with assistive technology navigation.
|
||||
- Add labels to `<input type="button">` or `<button>` elements (they have built-in labels via their content/value).
|
||||
|
||||
---
|
||||
|
||||
## `<legend>`
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/legend>
|
||||
|
||||
### Description
|
||||
|
||||
The `<legend>` element represents a caption for the content of its parent `<fieldset>`. It provides a semantic way to label grouped form controls.
|
||||
|
||||
### Key Details
|
||||
|
||||
- **Must be** the first child of a `<fieldset>` element.
|
||||
- Provides an accessible label for the entire fieldset group.
|
||||
- Only supports global attributes (no element-specific attributes).
|
||||
- Can contain phrasing content and headings (`h1`--`h6`).
|
||||
- DOM Interface: `HTMLLegendElement`.
|
||||
|
||||
### Example
|
||||
|
||||
```html
|
||||
<fieldset>
|
||||
<legend>Choose your favorite monster</legend>
|
||||
|
||||
<input type="radio" id="kraken" name="monster" value="K" />
|
||||
<label for="kraken">Kraken</label><br />
|
||||
|
||||
<input type="radio" id="sasquatch" name="monster" value="S" />
|
||||
<label for="sasquatch">Sasquatch</label>
|
||||
</fieldset>
|
||||
```
|
||||
|
||||
```css
|
||||
legend {
|
||||
background-color: black;
|
||||
color: white;
|
||||
padding: 3px 6px;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `<meter>`
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/meter>
|
||||
|
||||
### Description
|
||||
|
||||
The `<meter>` element represents a scalar value within a known range or a fractional value. It is commonly used to display measurements like fuel levels, temperature, disk usage, or ratings.
|
||||
|
||||
### Key Attributes
|
||||
|
||||
| Attribute | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `value` | `0` | Current numeric value (must be between `min` and `max`). |
|
||||
| `min` | `0` | Lower bound of the measured range. |
|
||||
| `max` | `1` | Upper bound of the measured range. |
|
||||
| `low` | `min` value | Upper bound of the "low" end of the range. |
|
||||
| `high` | `max` value | Lower bound of the "high" end of the range. |
|
||||
| `optimum` | -- | Optimal numeric value; indicates the preferred range section. |
|
||||
|
||||
### Usage Notes
|
||||
|
||||
- Unless the `value` is between 0 and 1, define `min` and `max` to ensure `value` falls within the range.
|
||||
- Browsers color the meter bar differently based on whether the value is below `low`, between `low` and `high`, above `high`, or relative to `optimum`.
|
||||
- Cannot contain nested `<meter>` elements.
|
||||
- Implicit ARIA role: `meter`.
|
||||
|
||||
### Difference from `<progress>`
|
||||
|
||||
- **`<meter>`**: Displays a scalar measurement within a range (e.g., temperature, disk usage).
|
||||
- **`<progress>`**: Displays task completion progress from 0 to max.
|
||||
|
||||
### Example
|
||||
|
||||
```html
|
||||
<!-- Simple battery level -->
|
||||
<p>Battery level: <meter min="0" max="100" value="75">75%</meter></p>
|
||||
|
||||
<!-- With low/high ranges -->
|
||||
<p>
|
||||
Student's exam score:
|
||||
<meter low="50" high="80" max="100" value="84">84%</meter>
|
||||
</p>
|
||||
|
||||
<!-- Complete example with optimum -->
|
||||
<label for="fuel">Fuel level:</label>
|
||||
<meter id="fuel" min="0" max="100" low="33" high="66" optimum="80" value="50">
|
||||
at 50/100
|
||||
</meter>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `<optgroup>`
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/optgroup>
|
||||
|
||||
### Description
|
||||
|
||||
The `<optgroup>` element creates a grouping of options within a `<select>` element, allowing you to organize related options into labeled groups.
|
||||
|
||||
### Key Attributes
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `label` | The name of the option group (**mandatory**). Browsers display this as a non-selectable label in the UI. |
|
||||
| `disabled` | Boolean attribute. When set, all options in this group become non-selectable and appear greyed out. |
|
||||
|
||||
### Usage Notes
|
||||
|
||||
- Must be a child of a `<select>` element.
|
||||
- Contains one or more `<option>` elements.
|
||||
- Cannot be nested within other `<optgroup>` elements.
|
||||
- The `label` attribute is **mandatory**.
|
||||
- Implicit ARIA role: `group`.
|
||||
|
||||
### Example
|
||||
|
||||
```html
|
||||
<label for="dino-select">Choose a dinosaur:</label>
|
||||
<select id="dino-select">
|
||||
<optgroup label="Theropods">
|
||||
<option>Tyrannosaurus</option>
|
||||
<option>Velociraptor</option>
|
||||
<option>Deinonychus</option>
|
||||
</optgroup>
|
||||
<optgroup label="Sauropods">
|
||||
<option>Diplodocus</option>
|
||||
<option>Saltasaurus</option>
|
||||
<option>Apatosaurus</option>
|
||||
</optgroup>
|
||||
<optgroup label="Extinct Groups" disabled>
|
||||
<option>Stegosaurus</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `<option>`
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/option>
|
||||
|
||||
### Description
|
||||
|
||||
The `<option>` element defines items contained within `<select>`, `<optgroup>`, or `<datalist>` elements. It represents individual menu items or selectable options.
|
||||
|
||||
### Key Attributes
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `value` | The value submitted with the form if the option is selected. If omitted, the element's text content is used. |
|
||||
| `selected` | Boolean attribute that marks the option as initially selected. Only one `<option>` per `<select>` (without `multiple`) can have this attribute. |
|
||||
| `disabled` | Boolean attribute that disables the option (greyed out, no interaction). Options are also disabled if their `<optgroup>` ancestor is disabled. |
|
||||
| `label` | Text label for the option. If not defined, the element's text content is used. |
|
||||
|
||||
### Context of Use
|
||||
|
||||
- **Within `<select>`**: Lists selectable options; users choose one (or multiple if `multiple` attribute is set on the select).
|
||||
- **Within `<optgroup>`**: Groups related options together.
|
||||
- **Within `<datalist>`**: Provides autocomplete suggestions for `<input>` elements.
|
||||
|
||||
### Usage Notes
|
||||
|
||||
- End tag is optional if immediately followed by another `<option>` or `<optgroup>`.
|
||||
- Implicit ARIA role: `option`.
|
||||
|
||||
### Example
|
||||
|
||||
```html
|
||||
<label for="pet-select">Choose a pet:</label>
|
||||
<select id="pet-select">
|
||||
<option value="">--Please choose an option--</option>
|
||||
<option value="dog">Dog</option>
|
||||
<option value="cat">Cat</option>
|
||||
<option value="hamster" disabled>Hamster</option>
|
||||
<option value="parrot" selected>Parrot</option>
|
||||
</select>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `<output>`
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/output>
|
||||
|
||||
### Description
|
||||
|
||||
The `<output>` element is a container element that displays the results of a calculation or the outcome of a user action. It is form-associated and is implemented as an ARIA live region by most browsers, meaning assistive technology will announce changes automatically.
|
||||
|
||||
### Key Attributes
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `for` | Space-separated list of element `id`s that contributed to the calculation. |
|
||||
| `form` | Associates the output with a specific `<form>` by its `id` (overrides ancestor forms). |
|
||||
| `name` | The element's name; used in `form.elements` API. |
|
||||
|
||||
### Usage Notes
|
||||
|
||||
- The `<output>` value, name, and contents are **not submitted** with the form.
|
||||
- Implemented as an `aria-live` region; assistive technology announces changes automatically.
|
||||
- Must have both opening and closing tags.
|
||||
|
||||
### Example
|
||||
|
||||
```html
|
||||
<form id="example-form">
|
||||
<input type="range" id="b" name="b" value="50" /> +
|
||||
<input type="number" id="a" name="a" value="10" /> =
|
||||
<output name="result" for="a b">60</output>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
const form = document.getElementById("example-form");
|
||||
form.addEventListener("input", () => {
|
||||
const result = form.elements["a"].valueAsNumber +
|
||||
form.elements["b"].valueAsNumber;
|
||||
form.elements["result"].value = result;
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `<progress>`
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/progress>
|
||||
|
||||
### Description
|
||||
|
||||
The `<progress>` element displays a progress indicator showing the completion of a task, typically rendered as a progress bar.
|
||||
|
||||
### Key Attributes
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `max` | Total amount of work required. Must be greater than 0 and a valid floating-point number. Default: `1`. |
|
||||
| `value` | Completed amount (0 to `max`, or 0 to 1 if `max` is omitted). If omitted, shows an indeterminate progress bar. |
|
||||
|
||||
### Difference from `<meter>`
|
||||
|
||||
- Minimum value is always 0 (the `min` attribute is **not allowed** for `<progress>`).
|
||||
- `<progress>` is specifically for task completion; `<meter>` is for scalar measurements.
|
||||
|
||||
### Usage Notes
|
||||
|
||||
- Both opening and closing tags are required.
|
||||
- Implicit ARIA role: `progressbar`.
|
||||
- Text between tags is fallback content for older browsers (not an accessible label).
|
||||
- Use the `:indeterminate` pseudo-class to style indeterminate progress bars.
|
||||
- Remove the `value` attribute (`element.removeAttribute('value')`) to make an indeterminate progress bar.
|
||||
|
||||
### Accessibility Considerations
|
||||
|
||||
- Always provide an accessible label using a `<label>` element, `aria-labelledby`, or `aria-label`.
|
||||
- For page sections that are loading: set `aria-busy="true"` on the section being updated, use `aria-describedby` to link to the progress element, and remove `aria-busy` when loading completes.
|
||||
|
||||
### Example
|
||||
|
||||
```html
|
||||
<!-- Basic progress bar -->
|
||||
<label for="file">File progress:</label>
|
||||
<progress id="file" max="100" value="70">70%</progress>
|
||||
|
||||
<!-- Accessible with implicit label -->
|
||||
<label>
|
||||
Uploading Document: <progress value="70" max="100">70%</progress>
|
||||
</label>
|
||||
|
||||
<!-- Indeterminate (no value attribute) -->
|
||||
<progress max="100"></progress>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `<select>`
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/select>
|
||||
|
||||
### Description
|
||||
|
||||
The `<select>` element represents a control that provides a menu of options, allowing users to select from a dropdown list of choices.
|
||||
|
||||
### Key Attributes
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `name` | Specifies the name of the control for form submission. |
|
||||
| `multiple` | Boolean attribute allowing selection of multiple options. |
|
||||
| `size` | Number of visible rows in a scrolling list box (default: `0`). |
|
||||
| `required` | Boolean attribute requiring a non-empty option selection. |
|
||||
| `disabled` | Boolean attribute preventing user interaction. |
|
||||
| `autofocus` | Boolean attribute giving focus to the control on page load. |
|
||||
| `form` | Associates the select with a specific form by ID. |
|
||||
| `autocomplete` | Provides hints for autocomplete behavior. |
|
||||
|
||||
### Usage Notes
|
||||
|
||||
- Each option is defined with nested `<option>` elements.
|
||||
- Use `<optgroup>` to group related options visually.
|
||||
- Use `<hr>` elements to create visual separators between options.
|
||||
- The `value` attribute on `<option>` elements specifies data submitted to the server.
|
||||
- If no `value` attribute exists on an option, the option's text content is used.
|
||||
- Without a `selected` attribute, the first option defaults as selected.
|
||||
- Multiple selections with `multiple` attribute are submitted as `name=value1&name=value2`.
|
||||
|
||||
### Accessibility Considerations
|
||||
|
||||
- Associate with labels using `<label>` with `for` attribute matching the select's `id`.
|
||||
- Implicit ARIA roles: `combobox` (single select), `listbox` (multiple or size > 1).
|
||||
|
||||
### Example
|
||||
|
||||
```html
|
||||
<label for="pet-select">Choose a pet:</label>
|
||||
|
||||
<select name="pets" id="pet-select">
|
||||
<option value="">--Please choose an option--</option>
|
||||
<option value="dog">Dog</option>
|
||||
<option value="cat">Cat</option>
|
||||
<option value="hamster">Hamster</option>
|
||||
</select>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `<textarea>`
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/textarea>
|
||||
|
||||
### Description
|
||||
|
||||
The `<textarea>` element represents a multi-line plain-text editing control for allowing users to enter sizeable amounts of free-form text (e.g., comments, feedback, reviews).
|
||||
|
||||
### Key Attributes
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `rows` | Number of visible text lines (default: `2`). |
|
||||
| `cols` | Visible width in average character widths (default: `20`). |
|
||||
| `name` | Control name for form submission. |
|
||||
| `id` | For associating with `<label>` elements. |
|
||||
| `placeholder` | Hint text displayed to the user. |
|
||||
| `maxlength` | Maximum string length (UTF-16 code units). |
|
||||
| `minlength` | Minimum string length (UTF-16 code units). |
|
||||
| `wrap` | Line wrapping behavior: `soft` (default), `hard`, or `off`. |
|
||||
| `disabled` | Boolean; disables user interaction. |
|
||||
| `readonly` | Boolean; user cannot modify content but it remains focusable and submittable. |
|
||||
| `required` | Boolean; user must fill in a value. |
|
||||
| `autocomplete` | `on` or `off` for browser auto-completion. |
|
||||
| `spellcheck` | `true`, `false`, or `default` for spell-checking behavior. |
|
||||
| `autofocus` | Boolean; receives focus on page load. |
|
||||
|
||||
### Usage Notes
|
||||
|
||||
- Initial content goes between opening and closing tags (not as a `value` attribute).
|
||||
- Use `.value` property in JavaScript to get/set content; `.defaultValue` for the initial value.
|
||||
- Resizable by default; disable resizing with `resize: none` in CSS.
|
||||
- Use `:valid` and `:invalid` pseudo-classes for styling based on `minlength`/`maxlength`/`required` constraints.
|
||||
|
||||
### Example
|
||||
|
||||
```html
|
||||
<label for="story">Tell us your story:</label>
|
||||
|
||||
<textarea
|
||||
id="story"
|
||||
name="story"
|
||||
rows="5"
|
||||
cols="33"
|
||||
placeholder="Enter your feedback here..."
|
||||
maxlength="500"
|
||||
required>
|
||||
It was a dark and stormy night...
|
||||
</textarea>
|
||||
```
|
||||
|
||||
```css
|
||||
textarea {
|
||||
padding: 10px;
|
||||
border: 1px solid #cccccc;
|
||||
border-radius: 5px;
|
||||
font-family: Arial, sans-serif;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
textarea:invalid {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
textarea:valid {
|
||||
border-color: green;
|
||||
}
|
||||
```
|
||||
990
skills/create-web-form/references/html-form-example.md
Normal file
990
skills/create-web-form/references/html-form-example.md
Normal file
@@ -0,0 +1,990 @@
|
||||
# HTML Form Examples Reference
|
||||
|
||||
This reference consolidates key educational content from W3Schools covering HTML forms, form elements, input types, and form-related attributes.
|
||||
|
||||
---
|
||||
|
||||
## HTML Forms
|
||||
|
||||
> **Source:** https://www.w3schools.com/html/html_forms.asp
|
||||
|
||||
### The `<form>` Element
|
||||
|
||||
The `<form>` element is used to create an HTML form for user input. It acts as a container for different types of input elements such as text fields, checkboxes, radio buttons, submit buttons, and more.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<!-- form elements go here -->
|
||||
</form>
|
||||
```
|
||||
|
||||
### The `<input>` Element
|
||||
|
||||
The `<input>` element is the most used form element. It can be displayed in many ways depending on the `type` attribute.
|
||||
|
||||
| Type | Description |
|
||||
|------|-------------|
|
||||
| `<input type="text">` | Displays a single-line text input field |
|
||||
| `<input type="radio">` | Displays a radio button (for selecting one of many choices) |
|
||||
| `<input type="checkbox">` | Displays a checkbox (for selecting zero or more of many choices) |
|
||||
| `<input type="submit">` | Displays a submit button (for submitting the form) |
|
||||
| `<input type="button">` | Displays a clickable button |
|
||||
|
||||
### Text Fields
|
||||
|
||||
The `<input type="text">` defines a single-line input field for text input.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<label for="fname">First name:</label><br>
|
||||
<input type="text" id="fname" name="fname"><br>
|
||||
<label for="lname">Last name:</label><br>
|
||||
<input type="text" id="lname" name="lname">
|
||||
</form>
|
||||
```
|
||||
|
||||
**Note:** The form itself is not visible. The default width of an input field is 20 characters.
|
||||
|
||||
### The `<label>` Element
|
||||
|
||||
The `<label>` element defines a label for many form elements. It is useful for screen-reader users because the screen reader will read the label aloud when the user focuses on the input element. It also helps users who have difficulty clicking on very small regions (such as radio buttons or checkboxes) because clicking on the label text toggles the associated input.
|
||||
|
||||
The `for` attribute of the `<label>` tag should be equal to the `id` attribute of the `<input>` element to bind them together.
|
||||
|
||||
### Radio Buttons
|
||||
|
||||
The `<input type="radio">` defines a radio button. Radio buttons let a user select ONE of a limited number of choices.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<p>Choose your favorite Web language:</p>
|
||||
<input type="radio" id="html" name="fav_language" value="HTML">
|
||||
<label for="html">HTML</label><br>
|
||||
<input type="radio" id="css" name="fav_language" value="CSS">
|
||||
<label for="css">CSS</label><br>
|
||||
<input type="radio" id="javascript" name="fav_language" value="JavaScript">
|
||||
<label for="javascript">JavaScript</label>
|
||||
</form>
|
||||
```
|
||||
|
||||
### Checkboxes
|
||||
|
||||
The `<input type="checkbox">` defines a checkbox. Checkboxes let a user select ZERO or MORE options of a limited number of choices.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<input type="checkbox" id="vehicle1" name="vehicle1" value="Bike">
|
||||
<label for="vehicle1"> I have a bike</label><br>
|
||||
<input type="checkbox" id="vehicle2" name="vehicle2" value="Car">
|
||||
<label for="vehicle2"> I have a car</label><br>
|
||||
<input type="checkbox" id="vehicle3" name="vehicle3" value="Boat">
|
||||
<label for="vehicle3"> I have a boat</label>
|
||||
</form>
|
||||
```
|
||||
|
||||
### The Submit Button
|
||||
|
||||
The `<input type="submit">` defines a button for submitting the form data to a form-handler. The form-handler is typically a file on the server with a script for processing input data, specified in the form's `action` attribute.
|
||||
|
||||
```html
|
||||
<form action="/action_page.php">
|
||||
<label for="fname">First name:</label><br>
|
||||
<input type="text" id="fname" name="fname" value="John"><br>
|
||||
<label for="lname">Last name:</label><br>
|
||||
<input type="text" id="lname" name="lname" value="Doe"><br><br>
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
```
|
||||
|
||||
### The `name` Attribute for `<input>`
|
||||
|
||||
Each input field must have a `name` attribute to be submitted. If the `name` attribute is omitted, the value of the input field will not be sent at all.
|
||||
|
||||
---
|
||||
|
||||
## HTML Form Attributes
|
||||
|
||||
> **Source:** https://www.w3schools.com/html/html_forms_attributes.asp
|
||||
|
||||
### The `action` Attribute
|
||||
|
||||
The `action` attribute defines the action to be performed when the form is submitted. Usually, the form data is sent to a file on the server when the user clicks the submit button.
|
||||
|
||||
```html
|
||||
<form action="/action_page.php">
|
||||
<label for="fname">First name:</label><br>
|
||||
<input type="text" id="fname" name="fname" value="John"><br>
|
||||
<label for="lname">Last name:</label><br>
|
||||
<input type="text" id="lname" name="lname" value="Doe"><br><br>
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
```
|
||||
|
||||
**Tip:** If the `action` attribute is omitted, the action is set to the current page.
|
||||
|
||||
### The `target` Attribute
|
||||
|
||||
The `target` attribute specifies where to display the response that is received after submitting the form.
|
||||
|
||||
| Value | Description |
|
||||
|-------|-------------|
|
||||
| `_blank` | The response is displayed in a new window or tab |
|
||||
| `_self` | The response is displayed in the current window (default) |
|
||||
| `_parent` | The response is displayed in the parent frame |
|
||||
| `_top` | The response is displayed in the full body of the window |
|
||||
| `framename` | The response is displayed in a named iframe |
|
||||
|
||||
```html
|
||||
<form action="/action_page.php" target="_blank">
|
||||
```
|
||||
|
||||
### The `method` Attribute
|
||||
|
||||
The `method` attribute specifies the HTTP method to be used when submitting the form data. The form data can be sent as URL variables (with `method="get"`) or as an HTTP post transaction (with `method="post"`).
|
||||
|
||||
```html
|
||||
<!-- Using GET -->
|
||||
<form action="/action_page.php" method="get">
|
||||
|
||||
<!-- Using POST -->
|
||||
<form action="/action_page.php" method="post">
|
||||
```
|
||||
|
||||
**When to use GET:**
|
||||
|
||||
- The default method if not specified
|
||||
- Form data is appended to the URL in name/value pairs
|
||||
- The length of a URL is limited (about 2048 characters)
|
||||
- Never use GET to send sensitive data (it will be visible in the URL)
|
||||
- Useful for form submissions where a user wants to bookmark the result
|
||||
- GET is suitable for non-secure data, like query strings in search engines
|
||||
|
||||
**When to use POST:**
|
||||
|
||||
- Appends the form data inside the body of the HTTP request (data is not shown in the URL)
|
||||
- POST has no size limitations
|
||||
- Form submissions with POST cannot be bookmarked
|
||||
- Always use POST when submitting sensitive or personal information
|
||||
|
||||
### The `autocomplete` Attribute
|
||||
|
||||
The `autocomplete` attribute specifies whether a form should have autocomplete on or off. When autocomplete is on, the browser automatically completes values based on values that the user has entered before.
|
||||
|
||||
```html
|
||||
<form action="/action_page.php" autocomplete="on">
|
||||
```
|
||||
|
||||
### The `novalidate` Attribute
|
||||
|
||||
The `novalidate` attribute is a boolean attribute. When present, it specifies that the form data should not be validated when submitted.
|
||||
|
||||
```html
|
||||
<form action="/action_page.php" novalidate>
|
||||
```
|
||||
|
||||
### The `enctype` Attribute
|
||||
|
||||
The `enctype` attribute specifies how the form data should be encoded when submitting it to the server. This attribute can only be used with `method="post"`.
|
||||
|
||||
| Value | Description |
|
||||
|-------|-------------|
|
||||
| `application/x-www-form-urlencoded` | Default. All characters are encoded before sent |
|
||||
| `multipart/form-data` | Required when the form includes file upload controls (`<input type="file">`) |
|
||||
| `text/plain` | Sends data without any encoding (not recommended) |
|
||||
|
||||
```html
|
||||
<form action="/action_page.php" method="post" enctype="multipart/form-data">
|
||||
```
|
||||
|
||||
### The `name` Attribute
|
||||
|
||||
The `name` attribute specifies the name of the form. It is used to reference elements in JavaScript, or to reference form data after submission. Only forms with a name attribute will have their values passed when submitted.
|
||||
|
||||
### The `accept-charset` Attribute
|
||||
|
||||
The `accept-charset` attribute specifies the character encodings used for the form submission. The default value is `"unknown"`, which indicates the same encoding as the document.
|
||||
|
||||
### All `<form>` Attributes Summary
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `accept-charset` | Specifies the character encodings for form submission |
|
||||
| `action` | Specifies where to send the form data when submitted |
|
||||
| `autocomplete` | Specifies whether the form should have autocomplete on or off |
|
||||
| `enctype` | Specifies how the form data should be encoded when submitting (for `method="post"`) |
|
||||
| `method` | Specifies the HTTP method to use when sending form data |
|
||||
| `name` | Specifies the name of the form |
|
||||
| `novalidate` | Specifies that the form should not be validated when submitted |
|
||||
| `rel` | Specifies the relationship between a linked resource and the current document |
|
||||
| `target` | Specifies where to display the response after submitting the form |
|
||||
|
||||
---
|
||||
|
||||
## HTML Form Elements
|
||||
|
||||
> **Source:** https://www.w3schools.com/html/html_form_elements.asp
|
||||
|
||||
### The `<input>` Element
|
||||
|
||||
The most important form element. Can be displayed in several ways depending on the `type` attribute. If `type` is omitted, the input field gets the default type `text`.
|
||||
|
||||
### The `<label>` Element
|
||||
|
||||
Defines a label for several form elements. The `for` attribute should equal the `id` of a related input to bind them. Users can also click the label to toggle focus/selection on the input control.
|
||||
|
||||
### The `<select>` Element
|
||||
|
||||
The `<select>` element defines a drop-down list.
|
||||
|
||||
```html
|
||||
<label for="cars">Choose a car:</label>
|
||||
<select id="cars" name="cars">
|
||||
<option value="volvo">Volvo</option>
|
||||
<option value="saab">Saab</option>
|
||||
<option value="fiat" selected>Fiat</option>
|
||||
<option value="audi">Audi</option>
|
||||
</select>
|
||||
```
|
||||
|
||||
- The `<option>` elements define options that can be selected.
|
||||
- By default, the first item in the drop-down list is selected.
|
||||
- The `selected` attribute pre-selects an option.
|
||||
- Use the `size` attribute to specify the number of visible values.
|
||||
- Use the `multiple` attribute to allow the user to select more than one value.
|
||||
|
||||
```html
|
||||
<!-- Visible values -->
|
||||
<select id="cars" name="cars" size="3">
|
||||
|
||||
<!-- Allow multiple selections -->
|
||||
<select id="cars" name="cars" size="4" multiple>
|
||||
```
|
||||
|
||||
### The `<textarea>` Element
|
||||
|
||||
The `<textarea>` element defines a multi-line input field (a text area).
|
||||
|
||||
```html
|
||||
<textarea name="message" rows="10" cols="30">
|
||||
The cat was playing in the garden.
|
||||
</textarea>
|
||||
```
|
||||
|
||||
- The `rows` attribute specifies the visible number of lines in a text area.
|
||||
- The `cols` attribute specifies the visible width of a text area.
|
||||
- You can also define the size with CSS using `height` and `width` properties.
|
||||
|
||||
```css
|
||||
textarea {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
}
|
||||
```
|
||||
|
||||
### The `<button>` Element
|
||||
|
||||
The `<button>` element defines a clickable button.
|
||||
|
||||
```html
|
||||
<button type="button" onclick="alert('Hello World!')">Click Me!</button>
|
||||
```
|
||||
|
||||
**Note:** Always specify the `type` attribute for the `<button>` element. Different browsers may use different default types.
|
||||
|
||||
### The `<fieldset>` and `<legend>` Elements
|
||||
|
||||
The `<fieldset>` element groups related data in a form. The `<legend>` element defines a caption for the `<fieldset>` element.
|
||||
|
||||
```html
|
||||
<form action="/action_page.php">
|
||||
<fieldset>
|
||||
<legend>Personalia:</legend>
|
||||
<label for="fname">First name:</label><br>
|
||||
<input type="text" id="fname" name="fname" value="John"><br>
|
||||
<label for="lname">Last name:</label><br>
|
||||
<input type="text" id="lname" name="lname" value="Doe"><br><br>
|
||||
<input type="submit" value="Submit">
|
||||
</fieldset>
|
||||
</form>
|
||||
```
|
||||
|
||||
### The `<datalist>` Element
|
||||
|
||||
The `<datalist>` element specifies a list of pre-defined options for an `<input>` element. Users will see a drop-down list of the pre-defined options as they input data. The `list` attribute of the `<input>` element must refer to the `id` attribute of the `<datalist>` element.
|
||||
|
||||
```html
|
||||
<form action="/action_page.php">
|
||||
<input list="browsers" name="browser">
|
||||
<datalist id="browsers">
|
||||
<option value="Edge">
|
||||
<option value="Firefox">
|
||||
<option value="Chrome">
|
||||
<option value="Opera">
|
||||
<option value="Safari">
|
||||
</datalist>
|
||||
<input type="submit">
|
||||
</form>
|
||||
```
|
||||
|
||||
### The `<output>` Element
|
||||
|
||||
The `<output>` element represents the result of a calculation (typically performed using JavaScript).
|
||||
|
||||
```html
|
||||
<form action="/action_page.php"
|
||||
oninput="x.value=parseInt(a.value)+parseInt(b.value)">
|
||||
0
|
||||
<input type="range" id="a" name="a" value="50">
|
||||
100 +
|
||||
<input type="number" id="b" name="b" value="50">
|
||||
=
|
||||
<output name="x" for="a b"></output>
|
||||
<br><br>
|
||||
<input type="submit">
|
||||
</form>
|
||||
```
|
||||
|
||||
### The `<optgroup>` Element
|
||||
|
||||
The `<optgroup>` element is used to group related options in a `<select>` element (drop-down list).
|
||||
|
||||
```html
|
||||
<label for="cars">Choose a car:</label>
|
||||
<select name="cars" id="cars">
|
||||
<optgroup label="Swedish Cars">
|
||||
<option value="volvo">Volvo</option>
|
||||
<option value="saab">Saab</option>
|
||||
</optgroup>
|
||||
<optgroup label="German Cars">
|
||||
<option value="mercedes">Mercedes</option>
|
||||
<option value="audi">Audi</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
```
|
||||
|
||||
### Form Elements Summary
|
||||
|
||||
| Element | Description |
|
||||
|---------|-------------|
|
||||
| `<form>` | Defines an HTML form for user input |
|
||||
| `<input>` | Defines an input control |
|
||||
| `<textarea>` | Defines a multiline input control (text area) |
|
||||
| `<label>` | Defines a label for an `<input>` element |
|
||||
| `<fieldset>` | Groups related elements in a form |
|
||||
| `<legend>` | Defines a caption for a `<fieldset>` element |
|
||||
| `<select>` | Defines a drop-down list |
|
||||
| `<optgroup>` | Defines a group of related options in a drop-down list |
|
||||
| `<option>` | Defines an option in a drop-down list |
|
||||
| `<button>` | Defines a clickable button |
|
||||
| `<datalist>` | Specifies a list of pre-defined options for input controls |
|
||||
| `<output>` | Defines the result of a calculation |
|
||||
|
||||
---
|
||||
|
||||
## HTML Form Input Types
|
||||
|
||||
> **Source:** https://www.w3schools.com/html/html_form_input_types.asp
|
||||
|
||||
### Input Type: text
|
||||
|
||||
`<input type="text">` defines a single-line text input field.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<label for="fname">First name:</label><br>
|
||||
<input type="text" id="fname" name="fname"><br>
|
||||
<label for="lname">Last name:</label><br>
|
||||
<input type="text" id="lname" name="lname">
|
||||
</form>
|
||||
```
|
||||
|
||||
### Input Type: password
|
||||
|
||||
`<input type="password">` defines a password field. The characters are masked (shown as asterisks or circles).
|
||||
|
||||
```html
|
||||
<form>
|
||||
<label for="username">Username:</label><br>
|
||||
<input type="text" id="username" name="username"><br>
|
||||
<label for="pwd">Password:</label><br>
|
||||
<input type="password" id="pwd" name="pwd">
|
||||
</form>
|
||||
```
|
||||
|
||||
### Input Type: submit
|
||||
|
||||
`<input type="submit">` defines a button for submitting form data to a form-handler. The form-handler is typically a server page specified by the form's `action` attribute.
|
||||
|
||||
```html
|
||||
<form action="/action_page.php">
|
||||
<label for="fname">First name:</label><br>
|
||||
<input type="text" id="fname" name="fname" value="John"><br>
|
||||
<label for="lname">Last name:</label><br>
|
||||
<input type="text" id="lname" name="lname" value="Doe"><br><br>
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
```
|
||||
|
||||
If you omit the submit button's `value` attribute, the button will get a default text.
|
||||
|
||||
### Input Type: reset
|
||||
|
||||
`<input type="reset">` defines a reset button that will reset all form values to their default values.
|
||||
|
||||
```html
|
||||
<form action="/action_page.php">
|
||||
<label for="fname">First name:</label><br>
|
||||
<input type="text" id="fname" name="fname" value="John"><br>
|
||||
<label for="lname">Last name:</label><br>
|
||||
<input type="text" id="lname" name="lname" value="Doe"><br><br>
|
||||
<input type="submit" value="Submit">
|
||||
<input type="reset">
|
||||
</form>
|
||||
```
|
||||
|
||||
### Input Type: radio
|
||||
|
||||
`<input type="radio">` defines a radio button. Radio buttons let a user select only ONE of a limited number of choices.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<input type="radio" id="html" name="fav_language" value="HTML">
|
||||
<label for="html">HTML</label><br>
|
||||
<input type="radio" id="css" name="fav_language" value="CSS">
|
||||
<label for="css">CSS</label><br>
|
||||
<input type="radio" id="javascript" name="fav_language" value="JavaScript">
|
||||
<label for="javascript">JavaScript</label>
|
||||
</form>
|
||||
```
|
||||
|
||||
### Input Type: checkbox
|
||||
|
||||
`<input type="checkbox">` defines a checkbox. Checkboxes let a user select ZERO or MORE options.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<input type="checkbox" id="vehicle1" name="vehicle1" value="Bike">
|
||||
<label for="vehicle1"> I have a bike</label><br>
|
||||
<input type="checkbox" id="vehicle2" name="vehicle2" value="Car">
|
||||
<label for="vehicle2"> I have a car</label><br>
|
||||
<input type="checkbox" id="vehicle3" name="vehicle3" value="Boat">
|
||||
<label for="vehicle3"> I have a boat</label>
|
||||
</form>
|
||||
```
|
||||
|
||||
### Input Type: button
|
||||
|
||||
`<input type="button">` defines a button.
|
||||
|
||||
```html
|
||||
<input type="button" onclick="alert('Hello World!')" value="Click Me!">
|
||||
```
|
||||
|
||||
### Input Type: color
|
||||
|
||||
`<input type="color">` is used for input fields that should contain a color. Depending on browser support, a color picker can be shown.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<label for="favcolor">Select your favorite color:</label>
|
||||
<input type="color" id="favcolor" name="favcolor" value="#ff0000">
|
||||
</form>
|
||||
```
|
||||
|
||||
### Input Type: date
|
||||
|
||||
`<input type="date">` is used for input fields that should contain a date. Depending on browser support, a date picker can be shown.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<label for="birthday">Birthday:</label>
|
||||
<input type="date" id="birthday" name="birthday">
|
||||
</form>
|
||||
```
|
||||
|
||||
You can use the `min` and `max` attributes to add restrictions:
|
||||
|
||||
```html
|
||||
<input type="date" id="datemin" name="datemin" min="2000-01-02">
|
||||
<input type="date" id="datemax" name="datemax" max="1979-12-31">
|
||||
```
|
||||
|
||||
### Input Type: datetime-local
|
||||
|
||||
`<input type="datetime-local">` specifies a date and time input field, with no time zone.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<label for="birthdaytime">Birthday (date and time):</label>
|
||||
<input type="datetime-local" id="birthdaytime" name="birthdaytime">
|
||||
</form>
|
||||
```
|
||||
|
||||
### Input Type: email
|
||||
|
||||
`<input type="email">` is used for input fields that should contain an e-mail address. Depending on browser support, the e-mail address can be automatically validated. Some smartphones recognize the email type and add `.com` to the keyboard.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<label for="email">Enter your email:</label>
|
||||
<input type="email" id="email" name="email">
|
||||
</form>
|
||||
```
|
||||
|
||||
### Input Type: file
|
||||
|
||||
`<input type="file">` defines a file-select field and a "Browse" button for file uploads.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<label for="myfile">Select a file:</label>
|
||||
<input type="file" id="myfile" name="myfile">
|
||||
</form>
|
||||
```
|
||||
|
||||
### Input Type: hidden
|
||||
|
||||
`<input type="hidden">` defines a hidden input field (not visible to the user). A hidden field lets web developers include data that cannot be seen or modified by users when a form is submitted.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<label for="fname">First name:</label>
|
||||
<input type="text" id="fname" name="fname"><br><br>
|
||||
<input type="hidden" id="custId" name="custId" value="3487">
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
```
|
||||
|
||||
### Input Type: image
|
||||
|
||||
`<input type="image">` defines an image as a submit button. The path to the image is specified in the `src` attribute.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<input type="image" src="img_submit.gif" alt="Submit" width="48" height="48">
|
||||
</form>
|
||||
```
|
||||
|
||||
### Input Type: month
|
||||
|
||||
`<input type="month">` allows the user to select a month and year.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<label for="bdaymonth">Birthday (month and year):</label>
|
||||
<input type="month" id="bdaymonth" name="bdaymonth">
|
||||
</form>
|
||||
```
|
||||
|
||||
### Input Type: number
|
||||
|
||||
`<input type="number">` defines a numeric input field. You can set restrictions on what numbers are accepted.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<label for="quantity">Quantity (between 1 and 5):</label>
|
||||
<input type="number" id="quantity" name="quantity" min="1" max="5">
|
||||
</form>
|
||||
```
|
||||
|
||||
**Input restrictions:**
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `disabled` | Specifies that an input field should be disabled |
|
||||
| `max` | Specifies the maximum value for an input field |
|
||||
| `maxlength` | Specifies the maximum number of characters for an input field |
|
||||
| `min` | Specifies the minimum value for an input field |
|
||||
| `pattern` | Specifies a regular expression to check the input value against |
|
||||
| `readonly` | Specifies that an input field is read only (cannot be changed) |
|
||||
| `required` | Specifies that an input field is required (must be filled out) |
|
||||
| `size` | Specifies the width (in characters) of an input field |
|
||||
| `step` | Specifies the legal number intervals for an input field |
|
||||
| `value` | Specifies the default value for an input field |
|
||||
|
||||
### Input Type: range
|
||||
|
||||
`<input type="range">` defines a control for entering a number whose exact value is not important (like a slider control). Default range is 0 to 100. You can set restrictions with `min`, `max`, and `step`.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<label for="vol">Volume (between 0 and 50):</label>
|
||||
<input type="range" id="vol" name="vol" min="0" max="50">
|
||||
</form>
|
||||
```
|
||||
|
||||
### Input Type: search
|
||||
|
||||
`<input type="search">` is used for search fields (behaves like a regular text field).
|
||||
|
||||
```html
|
||||
<form>
|
||||
<label for="gsearch">Search Google:</label>
|
||||
<input type="search" id="gsearch" name="gsearch">
|
||||
</form>
|
||||
```
|
||||
|
||||
### Input Type: tel
|
||||
|
||||
`<input type="tel">` is used for input fields that should contain a telephone number.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<label for="phone">Enter your phone number:</label>
|
||||
<input type="tel" id="phone" name="phone"
|
||||
pattern="[0-9]{3}-[0-9]{2}-[0-9]{3}">
|
||||
</form>
|
||||
```
|
||||
|
||||
### Input Type: time
|
||||
|
||||
`<input type="time">` allows the user to select a time (no time zone).
|
||||
|
||||
```html
|
||||
<form>
|
||||
<label for="appt">Select a time:</label>
|
||||
<input type="time" id="appt" name="appt">
|
||||
</form>
|
||||
```
|
||||
|
||||
### Input Type: url
|
||||
|
||||
`<input type="url">` is used for input fields that should contain a URL address. Depending on browser support, the url field can be automatically validated. Some smartphones recognize the url type and add `.com` to the keyboard.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<label for="homepage">Add your homepage:</label>
|
||||
<input type="url" id="homepage" name="homepage">
|
||||
</form>
|
||||
```
|
||||
|
||||
### Input Type: week
|
||||
|
||||
`<input type="week">` allows the user to select a week and year.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<label for="week">Select a week:</label>
|
||||
<input type="week" id="week" name="week">
|
||||
</form>
|
||||
```
|
||||
|
||||
### Input Types Summary
|
||||
|
||||
| Input Type | Description |
|
||||
|------------|-------------|
|
||||
| `text` | Default. Single-line text input |
|
||||
| `password` | Password field (characters are masked) |
|
||||
| `submit` | Submit button |
|
||||
| `reset` | Reset button |
|
||||
| `radio` | Radio button |
|
||||
| `checkbox` | Checkbox |
|
||||
| `button` | Clickable button |
|
||||
| `color` | Color picker |
|
||||
| `date` | Date control (year, month, day) |
|
||||
| `datetime-local` | Date and time control (no timezone) |
|
||||
| `email` | Field for an e-mail address |
|
||||
| `file` | File-select field and a "Browse" button |
|
||||
| `hidden` | Hidden input field |
|
||||
| `image` | Image as a submit button |
|
||||
| `month` | Month and year control |
|
||||
| `number` | Field for entering a number |
|
||||
| `range` | Slider control for entering a number in a range |
|
||||
| `search` | Text field for searching |
|
||||
| `tel` | Field for entering a telephone number |
|
||||
| `time` | Control for entering a time |
|
||||
| `url` | Field for entering a URL |
|
||||
| `week` | Week and year control |
|
||||
|
||||
---
|
||||
|
||||
## HTML Input Attributes
|
||||
|
||||
> **Source:** https://www.w3schools.com/html/html_form_attributes.asp
|
||||
|
||||
### The `value` Attribute
|
||||
|
||||
The `value` attribute specifies an initial value for an input field.
|
||||
|
||||
```html
|
||||
<form>
|
||||
<label for="fname">First name:</label><br>
|
||||
<input type="text" id="fname" name="fname" value="John"><br>
|
||||
<label for="lname">Last name:</label><br>
|
||||
<input type="text" id="lname" name="lname" value="Doe">
|
||||
</form>
|
||||
```
|
||||
|
||||
### The `readonly` Attribute
|
||||
|
||||
The `readonly` attribute specifies that an input field is read-only. A read-only input field cannot be modified but can be tabbed to, highlighted, and copied. The value of a read-only field will be sent when submitting the form.
|
||||
|
||||
```html
|
||||
<input type="text" id="fname" name="fname" value="John" readonly>
|
||||
```
|
||||
|
||||
### The `disabled` Attribute
|
||||
|
||||
The `disabled` attribute specifies that an input field should be disabled. A disabled field is unusable and un-clickable. The value of a disabled field will **not** be sent when submitting the form.
|
||||
|
||||
```html
|
||||
<input type="text" id="fname" name="fname" value="John" disabled>
|
||||
```
|
||||
|
||||
### The `size` Attribute
|
||||
|
||||
The `size` attribute specifies the visible width, in characters, of an input field. The default value for `size` is 20. Works with: text, search, tel, url, email, and password.
|
||||
|
||||
```html
|
||||
<input type="text" id="fname" name="fname" size="50">
|
||||
```
|
||||
|
||||
### The `maxlength` Attribute
|
||||
|
||||
The `maxlength` attribute specifies the maximum number of characters allowed in an input field. When a `maxlength` is set, the input field will not accept more than the specified number of characters.
|
||||
|
||||
```html
|
||||
<input type="text" id="fname" name="fname" maxlength="10">
|
||||
```
|
||||
|
||||
### The `min` and `max` Attributes
|
||||
|
||||
The `min` and `max` attributes specify the minimum and maximum values for an input field. Work with: number, range, date, datetime-local, month, time, and week.
|
||||
|
||||
```html
|
||||
<input type="date" id="datemin" name="datemin" min="2000-01-02">
|
||||
<input type="date" id="datemax" name="datemax" max="1979-12-31">
|
||||
<input type="number" id="quantity" name="quantity" min="1" max="5">
|
||||
```
|
||||
|
||||
### The `multiple` Attribute
|
||||
|
||||
The `multiple` attribute specifies that the user is allowed to enter more than one value in an input field. Works with email and file.
|
||||
|
||||
```html
|
||||
<input type="file" id="files" name="files" multiple>
|
||||
```
|
||||
|
||||
### The `pattern` Attribute
|
||||
|
||||
The `pattern` attribute specifies a regular expression that the input field's value is checked against when the form is submitted. Works with: text, date, search, url, tel, email, and password.
|
||||
|
||||
```html
|
||||
<input type="text" id="country_code" name="country_code"
|
||||
pattern="[A-Za-z]{3}" title="Three letter country code">
|
||||
```
|
||||
|
||||
**Tip:** Use the global `title` attribute to describe the pattern to help the user.
|
||||
|
||||
### The `placeholder` Attribute
|
||||
|
||||
The `placeholder` attribute specifies a short hint that describes the expected value of an input field. The hint is displayed in the input field before the user enters a value. Works with: text, search, url, tel, email, and password.
|
||||
|
||||
```html
|
||||
<input type="tel" id="phone" name="phone"
|
||||
placeholder="123-45-678">
|
||||
```
|
||||
|
||||
### The `required` Attribute
|
||||
|
||||
The `required` attribute specifies that an input field must be filled out before submitting the form.
|
||||
|
||||
```html
|
||||
<input type="text" id="username" name="username" required>
|
||||
```
|
||||
|
||||
### The `step` Attribute
|
||||
|
||||
The `step` attribute specifies the legal number intervals for an input field. Works with: number, range, date, datetime-local, month, time, and week.
|
||||
|
||||
```html
|
||||
<!-- Accept values at intervals of 3 -->
|
||||
<input type="number" id="points" name="points" step="3">
|
||||
```
|
||||
|
||||
**Note:** Input restrictions are not foolproof. JavaScript provides additional ways to restrict illegal input. Server-side validation is always required.
|
||||
|
||||
### The `autofocus` Attribute
|
||||
|
||||
The `autofocus` attribute specifies that an input field should automatically get focus when the page loads.
|
||||
|
||||
```html
|
||||
<input type="text" id="fname" name="fname" autofocus>
|
||||
```
|
||||
|
||||
### The `height` and `width` Attributes
|
||||
|
||||
The `height` and `width` attributes specify the height and width of an `<input type="image">` element. Always specify the size of images to prevent page flickering during load.
|
||||
|
||||
```html
|
||||
<input type="image" src="img_submit.gif" alt="Submit" width="48" height="48">
|
||||
```
|
||||
|
||||
### The `list` Attribute
|
||||
|
||||
The `list` attribute refers to a `<datalist>` element that contains pre-defined options for an `<input>` element.
|
||||
|
||||
```html
|
||||
<input list="browsers">
|
||||
<datalist id="browsers">
|
||||
<option value="Edge">
|
||||
<option value="Firefox">
|
||||
<option value="Chrome">
|
||||
<option value="Opera">
|
||||
<option value="Safari">
|
||||
</datalist>
|
||||
```
|
||||
|
||||
### The `autocomplete` Attribute
|
||||
|
||||
The `autocomplete` attribute specifies whether a form or an input field should have autocomplete on or off. When on, the browser automatically completes values based on previously entered values.
|
||||
|
||||
```html
|
||||
<form action="/action_page.php" autocomplete="on">
|
||||
<label for="fname">First name:</label>
|
||||
<input type="text" id="fname" name="fname"><br><br>
|
||||
<label for="email">Email:</label>
|
||||
<input type="email" id="email" name="email" autocomplete="off"><br><br>
|
||||
<input type="submit">
|
||||
</form>
|
||||
```
|
||||
|
||||
**Tip:** `autocomplete` works with the `<form>` element and the following `<input>` types: text, search, url, tel, email, password, datepickers, range, and color.
|
||||
|
||||
### Input Attributes Summary
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `value` | Specifies the default value of an input element |
|
||||
| `readonly` | Specifies that an input field is read-only |
|
||||
| `disabled` | Specifies that an input field is disabled |
|
||||
| `size` | Specifies the visible width of an input field |
|
||||
| `maxlength` | Specifies the maximum number of characters in an input field |
|
||||
| `min` | Specifies the minimum value for an input field |
|
||||
| `max` | Specifies the maximum value for an input field |
|
||||
| `multiple` | Specifies that a user can enter more than one value |
|
||||
| `pattern` | Specifies a regular expression to check the value against |
|
||||
| `placeholder` | Specifies a short hint describing the expected value |
|
||||
| `required` | Specifies that an input field must be filled out |
|
||||
| `step` | Specifies the legal number intervals |
|
||||
| `autofocus` | Specifies that an input field should get focus on page load |
|
||||
| `height` | Specifies the height of an `<input type="image">` |
|
||||
| `width` | Specifies the width of an `<input type="image">` |
|
||||
| `list` | Refers to a `<datalist>` element with pre-defined options |
|
||||
| `autocomplete` | Specifies whether autocomplete is on or off |
|
||||
|
||||
---
|
||||
|
||||
## HTML Input form* Attributes
|
||||
|
||||
> **Source:** https://www.w3schools.com/html/html_form_attributes_form.asp
|
||||
|
||||
### The `form` Attribute
|
||||
|
||||
The input `form` attribute specifies the form the `<input>` element belongs to. The value of this attribute must be equal to the `id` attribute of the `<form>` element it belongs to. This allows an input field located outside the form to still be associated with it.
|
||||
|
||||
```html
|
||||
<form action="/action_page.php" id="form1">
|
||||
<label for="fname">First name:</label>
|
||||
<input type="text" id="fname" name="fname"><br><br>
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
|
||||
<!-- This input is outside the form but still part of it -->
|
||||
<label for="lname">Last name:</label>
|
||||
<input type="text" id="lname" name="lname" form="form1">
|
||||
```
|
||||
|
||||
### The `formaction` Attribute
|
||||
|
||||
The input `formaction` attribute specifies the URL of the file that will process the input when the form is submitted. This attribute overrides the `action` attribute of the `<form>` element. Works with submit and image input types.
|
||||
|
||||
```html
|
||||
<form action="/action_page.php">
|
||||
<label for="fname">First name:</label>
|
||||
<input type="text" id="fname" name="fname"><br><br>
|
||||
<input type="submit" value="Submit">
|
||||
<input type="submit" formaction="/action_page2.php" value="Submit as Admin">
|
||||
</form>
|
||||
```
|
||||
|
||||
### The `formenctype` Attribute
|
||||
|
||||
The input `formenctype` attribute specifies how the form data should be encoded when submitted (only for forms with `method="post"`). This attribute overrides the `enctype` attribute of the `<form>` element. Works with submit and image input types.
|
||||
|
||||
```html
|
||||
<form action="/action_page_binary.asp" method="post">
|
||||
<label for="fname">First name:</label>
|
||||
<input type="text" id="fname" name="fname"><br><br>
|
||||
<input type="submit" value="Submit">
|
||||
<input type="submit" formenctype="multipart/form-data"
|
||||
value="Submit as Multipart/form-data">
|
||||
</form>
|
||||
```
|
||||
|
||||
### The `formmethod` Attribute
|
||||
|
||||
The input `formmethod` attribute defines the HTTP method for sending form data to the action URL. This attribute overrides the `method` attribute of the `<form>` element. Works with submit and image input types.
|
||||
|
||||
```html
|
||||
<form action="/action_page.php" method="get">
|
||||
<label for="fname">First name:</label>
|
||||
<input type="text" id="fname" name="fname"><br><br>
|
||||
<label for="lname">Last name:</label>
|
||||
<input type="text" id="lname" name="lname"><br><br>
|
||||
<input type="submit" value="Submit using GET">
|
||||
<input type="submit" formmethod="post" value="Submit using POST">
|
||||
</form>
|
||||
```
|
||||
|
||||
### The `formtarget` Attribute
|
||||
|
||||
The input `formtarget` attribute specifies a name or keyword that indicates where to display the response after submitting the form. This attribute overrides the `target` attribute of the `<form>` element. Works with submit and image input types.
|
||||
|
||||
```html
|
||||
<form action="/action_page.php">
|
||||
<label for="fname">First name:</label>
|
||||
<input type="text" id="fname" name="fname"><br><br>
|
||||
<label for="lname">Last name:</label>
|
||||
<input type="text" id="lname" name="lname"><br><br>
|
||||
<input type="submit" value="Submit">
|
||||
<input type="submit" formtarget="_blank" value="Submit to a new window/tab">
|
||||
</form>
|
||||
```
|
||||
|
||||
### The `formnovalidate` Attribute
|
||||
|
||||
The input `formnovalidate` attribute specifies that an `<input>` element should not be validated when submitted. This attribute overrides the `novalidate` attribute of the `<form>` element. Works with the submit input type.
|
||||
|
||||
```html
|
||||
<form action="/action_page.php">
|
||||
<label for="email">Enter your email:</label>
|
||||
<input type="email" id="email" name="email"><br><br>
|
||||
<input type="submit" value="Submit">
|
||||
<input type="submit" formnovalidate="formnovalidate"
|
||||
value="Submit without validation">
|
||||
</form>
|
||||
```
|
||||
|
||||
### The `novalidate` Attribute
|
||||
|
||||
The `novalidate` attribute is a `<form>` attribute. When present, it specifies that all form data should not be validated when submitted.
|
||||
|
||||
```html
|
||||
<form action="/action_page.php" novalidate>
|
||||
<label for="email">Enter your email:</label>
|
||||
<input type="email" id="email" name="email"><br><br>
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
```
|
||||
|
||||
### form* Attributes Summary
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `form` | Specifies the form the input element belongs to |
|
||||
| `formaction` | Specifies the URL for form submission (overrides form's `action`) |
|
||||
| `formenctype` | Specifies how form data should be encoded (overrides form's `enctype`) |
|
||||
| `formmethod` | Specifies the HTTP method for sending data (overrides form's `method`) |
|
||||
| `formnovalidate` | Specifies that the input should not be validated (overrides form's `novalidate`) |
|
||||
| `formtarget` | Specifies where to display the response (overrides form's `target`) |
|
||||
1227
skills/create-web-form/references/hypertext-transfer-protocol.md
Normal file
1227
skills/create-web-form/references/hypertext-transfer-protocol.md
Normal file
File diff suppressed because it is too large
Load Diff
2413
skills/create-web-form/references/javascript.md
Normal file
2413
skills/create-web-form/references/javascript.md
Normal file
File diff suppressed because it is too large
Load Diff
145
skills/create-web-form/references/php-cookies.md
Normal file
145
skills/create-web-form/references/php-cookies.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# PHP Cookies Reference
|
||||
|
||||
> Source: <https://www.w3schools.com/php/php_cookies.asp>
|
||||
|
||||
## What is a Cookie?
|
||||
|
||||
A cookie is often used to identify a user. It is a small file that the server embeds on the user's computer. Each time the same computer requests a page with a browser, it will send the cookie too. With PHP, you can both create and retrieve cookie values.
|
||||
|
||||
## Create a Cookie with `setcookie()`
|
||||
|
||||
A cookie is created with the `setcookie()` function.
|
||||
|
||||
### Syntax
|
||||
|
||||
```php
|
||||
setcookie(name, value, expire, path, domain, secure, httponly);
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
| Parameter | Description |
|
||||
|------------|---------------------------------------------------------------------------------------------------------|
|
||||
| `name` | Required. Specifies the name of the cookie. |
|
||||
| `value` | Optional. Specifies the value of the cookie. |
|
||||
| `expire` | Optional. Specifies when the cookie expires. The value `time() + 86400 * 30` will set the cookie to expire in 30 days. If this parameter is omitted or set to `0`, the cookie will expire at the end of the session (when the browser closes). Default is `0`. |
|
||||
| `path` | Optional. Specifies the server path of the cookie. If set to `"/"`, the cookie will be available within the entire domain. If set to `"/php/"`, the cookie will only be available within the `php` directory and all sub-directories of `php`. The default value is the current directory that the cookie is being set in. |
|
||||
| `domain` | Optional. Specifies the domain name of the cookie. To make the cookie available on all subdomains of `example.com`, set domain to `".example.com"`. |
|
||||
| `secure` | Optional. Specifies whether or not the cookie should only be transmitted over a secure HTTPS connection. `true` means the cookie will only be set if a secure connection exists. Default is `false`. |
|
||||
| `httponly` | Optional. If set to `true` the cookie will be accessible only through the HTTP protocol (the cookie will not be accessible by scripting languages, such as JavaScript). This setting can help to reduce identity theft through XSS attacks. Default is `false`. |
|
||||
|
||||
**Note:** The `setcookie()` function must appear BEFORE the `<html>` tag (before any output is sent to the browser).
|
||||
|
||||
### Example: Create a Cookie
|
||||
|
||||
The following example creates a cookie named "user" with the value "John Doe". The cookie will expire after 30 days. The `"/"` means that the cookie is available across the entire website:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$cookie_name = "user";
|
||||
$cookie_value = "John Doe";
|
||||
setcookie($cookie_name, $cookie_value, time() + (86400 * 30), "/"); // 86400 = 1 day
|
||||
?>
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<?php
|
||||
if(!isset($_COOKIE[$cookie_name])) {
|
||||
echo "Cookie named '" . $cookie_name . "' is not set!";
|
||||
} else {
|
||||
echo "Cookie '" . $cookie_name . "' is set!<br>";
|
||||
echo "Value is: " . $_COOKIE[$cookie_name];
|
||||
}
|
||||
?>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
**Note:** The `setcookie()` function sends the cookie as part of the HTTP response header. A cookie is not visible to the current page until the next loading of a page that the cookie should be visible for. So to test the cookie, the page must be reloaded or another page must be navigated to.
|
||||
|
||||
## Retrieve a Cookie Value
|
||||
|
||||
The PHP `$_COOKIE` superglobal variable is used to retrieve a cookie value.
|
||||
|
||||
```php
|
||||
<?php
|
||||
if(!isset($_COOKIE["user"])) {
|
||||
echo "Cookie named 'user' is not set!";
|
||||
} else {
|
||||
echo "Cookie 'user' is set!<br>";
|
||||
echo "Value is: " . $_COOKIE["user"];
|
||||
}
|
||||
?>
|
||||
```
|
||||
|
||||
**Tip:** Use the `isset()` function to find out if a cookie is set before attempting to access its value.
|
||||
|
||||
## Modify a Cookie Value
|
||||
|
||||
To modify a cookie, just set (again) the cookie using the `setcookie()` function:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$cookie_name = "user";
|
||||
$cookie_value = "Alex Porter";
|
||||
setcookie($cookie_name, $cookie_value, time() + (86400 * 30), "/");
|
||||
?>
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<?php
|
||||
if(!isset($_COOKIE[$cookie_name])) {
|
||||
echo "Cookie named '" . $cookie_name . "' is not set!";
|
||||
} else {
|
||||
echo "Cookie '" . $cookie_name . "' is set!<br>";
|
||||
echo "Value is: " . $_COOKIE[$cookie_name];
|
||||
}
|
||||
?>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## Delete a Cookie
|
||||
|
||||
To delete a cookie, use the `setcookie()` function with an expiration date in the past:
|
||||
|
||||
```php
|
||||
<?php
|
||||
// Set the expiration date to one hour ago
|
||||
setcookie("user", "", time() - 3600);
|
||||
?>
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<?php
|
||||
echo "Cookie 'user' is deleted.";
|
||||
?>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## Check if Cookies are Enabled
|
||||
|
||||
The following example creates a small script that checks whether cookies are enabled. First, try to create a test cookie with the `setcookie()` function, then count the `$_COOKIE` array variable:
|
||||
|
||||
```php
|
||||
<?php
|
||||
setcookie("test_cookie", "test", time() + 3600, '/');
|
||||
?>
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<?php
|
||||
if(count($_COOKIE) > 0) {
|
||||
echo "Cookies are enabled.";
|
||||
} else {
|
||||
echo "Cookies are disabled.";
|
||||
}
|
||||
?>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
601
skills/create-web-form/references/php-forms.md
Normal file
601
skills/create-web-form/references/php-forms.md
Normal file
@@ -0,0 +1,601 @@
|
||||
# PHP Forms Reference
|
||||
|
||||
This reference consolidates key educational content from W3Schools covering PHP form handling, validation, required fields, URL/email validation, and a complete working example.
|
||||
|
||||
---
|
||||
|
||||
## PHP Form Handling
|
||||
|
||||
> **Source:** <https://www.w3schools.com/php/php_forms.asp>
|
||||
|
||||
### How PHP Forms Work
|
||||
|
||||
The PHP superglobals `$_GET` and `$_POST` are used to collect form data. When a user fills out a form and clicks submit, the form data is sent to a PHP file specified in the `action` attribute of the `<form>` tag.
|
||||
|
||||
### A Simple HTML Form
|
||||
|
||||
```html
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<form action="welcome.php" method="post">
|
||||
Name: <input type="text" name="name"><br>
|
||||
E-mail: <input type="text" name="email"><br>
|
||||
<input type="submit">
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
When the user fills out the form and clicks submit, the form data is sent via HTTP POST to `welcome.php`. The processing file can then access the data:
|
||||
|
||||
```php
|
||||
<html>
|
||||
<body>
|
||||
|
||||
Welcome <?php echo $_POST["name"]; ?><br>
|
||||
Your email address is: <?php echo $_POST["email"]; ?>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### Using the GET Method
|
||||
|
||||
```html
|
||||
<form action="welcome_get.php" method="get">
|
||||
Name: <input type="text" name="name"><br>
|
||||
E-mail: <input type="text" name="email"><br>
|
||||
<input type="submit">
|
||||
</form>
|
||||
```
|
||||
|
||||
```php
|
||||
<html>
|
||||
<body>
|
||||
|
||||
Welcome <?php echo $_GET["name"]; ?><br>
|
||||
Your email address is: <?php echo $_GET["email"]; ?>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### GET vs. POST
|
||||
|
||||
| Feature | GET | POST |
|
||||
|---------|-----|------|
|
||||
| Visibility | Data is visible in the URL (as query string parameters) | Data is NOT displayed in the URL |
|
||||
| Bookmarking | Pages can be bookmarked with query string values | Pages cannot be bookmarked with submitted data |
|
||||
| Data length | Limited (max URL length is approximately 2048 characters) | No limitations on data size |
|
||||
| Security | Should NEVER be used for sending sensitive data (passwords, etc.) | More secure than GET for sensitive data |
|
||||
| Caching | Requests can be cached | Requests are not cached |
|
||||
| Browser history | Parameters remain in browser history | Parameters are not saved in browser history |
|
||||
| Use case | Non-sensitive data, search queries, filter parameters | Sensitive data, form submissions that change data |
|
||||
|
||||
**Important:** Both `$_GET` and `$_POST` are superglobal arrays. They are always accessible regardless of scope, and you can access them from any function, class, or file without having to do anything special.
|
||||
|
||||
---
|
||||
|
||||
## PHP Form Validation
|
||||
|
||||
> **Source:** <https://www.w3schools.com/php/php_form_validation.asp>
|
||||
|
||||
### Think Security When Processing PHP Forms
|
||||
|
||||
These pages show how to process PHP forms with security in mind. Proper validation of form data is important to protect your form from hackers and spammers.
|
||||
|
||||
### The HTML Form
|
||||
|
||||
The form used throughout this tutorial:
|
||||
|
||||
- **Fields:** Name, E-mail, Website, Comment, Gender
|
||||
- **Validation rules:**
|
||||
|
||||
| Field | Validation Rules |
|
||||
|---------|-----------------|
|
||||
| Name | Required. Must only contain letters and whitespace |
|
||||
| E-mail | Required. Must contain a valid email address (with `@` and `.`) |
|
||||
| Website | Optional. If present, must contain a valid URL |
|
||||
| Comment | Optional. Multi-line input field (textarea) |
|
||||
| Gender | Required. Must select one |
|
||||
|
||||
### The Form Element
|
||||
|
||||
```html
|
||||
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>">
|
||||
```
|
||||
|
||||
The `$_SERVER["PHP_SELF"]` variable returns the filename of the currently executing script. So the form data is sent to the page itself instead of a different page.
|
||||
|
||||
### What is `$_SERVER["PHP_SELF"]`?
|
||||
|
||||
`$_SERVER["PHP_SELF"]` is a superglobal variable that returns the filename of the currently executing script relative to the document root.
|
||||
|
||||
### Big Note on PHP Form Security
|
||||
|
||||
The `$_SERVER["PHP_SELF"]` variable can be exploited by hackers via **Cross-Site Scripting (XSS)** attacks.
|
||||
|
||||
**XSS** enables attackers to inject client-side script into web pages viewed by other users. For example, if the form is on a page called `test_form.php`, a user could enter the following URL:
|
||||
|
||||
```
|
||||
http://www.example.com/test_form.php/%22%3E%3Cscript%3Ealert('hacked')%3C/script%3E
|
||||
```
|
||||
|
||||
This translates to:
|
||||
|
||||
```html
|
||||
<form method="post" action="test_form.php/"><script>alert('hacked')</script>
|
||||
```
|
||||
|
||||
The `<script>` tag is added and the `alert` command is executed. This is just a simple example. Any JavaScript code can be added inside `<script>` tags, and a hacker could redirect the user to a file on another server that holds malicious code that can alter global variables or submit the form to another address.
|
||||
|
||||
### How to Avoid `$_SERVER["PHP_SELF"]` Exploits
|
||||
|
||||
Use `htmlspecialchars()`:
|
||||
|
||||
```php
|
||||
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>">
|
||||
```
|
||||
|
||||
The `htmlspecialchars()` function converts special characters to HTML entities. Now if a user tries to exploit `PHP_SELF`, the output is safely rendered as:
|
||||
|
||||
```html
|
||||
<form method="post" action="test_form.php/"><script>alert('hacked')</script>">
|
||||
```
|
||||
|
||||
The exploit attempt fails because the code is escaped and treated as plain text.
|
||||
|
||||
### Validate Form Data with PHP
|
||||
|
||||
1. Strip unnecessary characters (extra spaces, tabs, newlines) from user input with `trim()`
|
||||
2. Remove backslashes from user input with `stripslashes()`
|
||||
3. Convert special characters to HTML entities with `htmlspecialchars()`
|
||||
|
||||
### The `test_input()` Function
|
||||
|
||||
Create a reusable function to do all the checking:
|
||||
|
||||
```php
|
||||
<?php
|
||||
function test_input($data) {
|
||||
$data = trim($data);
|
||||
$data = stripslashes($data);
|
||||
$data = htmlspecialchars($data);
|
||||
return $data;
|
||||
}
|
||||
?>
|
||||
```
|
||||
|
||||
### Processing the Form
|
||||
|
||||
```php
|
||||
<?php
|
||||
// Define variables and set to empty values
|
||||
$name = $email = $gender = $comment = $website = "";
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
$name = test_input($_POST["name"]);
|
||||
$email = test_input($_POST["email"]);
|
||||
$website = test_input($_POST["website"]);
|
||||
$comment = test_input($_POST["comment"]);
|
||||
$gender = test_input($_POST["gender"]);
|
||||
}
|
||||
?>
|
||||
```
|
||||
|
||||
**Important:** At the start of the script, we check whether the form has been submitted using `$_SERVER["REQUEST_METHOD"]`. If the `REQUEST_METHOD` is `POST`, then the form has been submitted and it should be validated.
|
||||
|
||||
---
|
||||
|
||||
## PHP Form Required Fields
|
||||
|
||||
> **Source:** <https://www.w3schools.com/php/php_form_required.asp>
|
||||
|
||||
### Making Fields Required
|
||||
|
||||
In the previous section, all input fields were optional. In this section, we add validation to make certain fields required and create error messages when needed.
|
||||
|
||||
### Adding Error Variables
|
||||
|
||||
Define error variables for each required field and initialize them as empty:
|
||||
|
||||
```php
|
||||
<?php
|
||||
// Define variables and set to empty values
|
||||
$nameErr = $emailErr = $genderErr = $websiteErr = "";
|
||||
$name = $email = $gender = $comment = $website = "";
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
if (empty($_POST["name"])) {
|
||||
$nameErr = "Name is required";
|
||||
} else {
|
||||
$name = test_input($_POST["name"]);
|
||||
}
|
||||
|
||||
if (empty($_POST["email"])) {
|
||||
$emailErr = "Email is required";
|
||||
} else {
|
||||
$email = test_input($_POST["email"]);
|
||||
}
|
||||
|
||||
if (empty($_POST["website"])) {
|
||||
$website = "";
|
||||
} else {
|
||||
$website = test_input($_POST["website"]);
|
||||
}
|
||||
|
||||
if (empty($_POST["comment"])) {
|
||||
$comment = "";
|
||||
} else {
|
||||
$comment = test_input($_POST["comment"]);
|
||||
}
|
||||
|
||||
if (empty($_POST["gender"])) {
|
||||
$genderErr = "Gender is required";
|
||||
} else {
|
||||
$gender = test_input($_POST["gender"]);
|
||||
}
|
||||
}
|
||||
?>
|
||||
```
|
||||
|
||||
### The `empty()` Function
|
||||
|
||||
The `empty()` function checks whether a variable is empty, null, or has a falsy value. It returns `true` for empty strings, `null`, `0`, `"0"`, `false`, and undefined variables.
|
||||
|
||||
### Displaying Error Messages
|
||||
|
||||
In the HTML form, display the error messages next to the corresponding fields:
|
||||
|
||||
```html
|
||||
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>">
|
||||
|
||||
Name: <input type="text" name="name">
|
||||
<span class="error">* <?php echo $nameErr; ?></span>
|
||||
<br><br>
|
||||
|
||||
E-mail: <input type="text" name="email">
|
||||
<span class="error">* <?php echo $emailErr; ?></span>
|
||||
<br><br>
|
||||
|
||||
Website: <input type="text" name="website">
|
||||
<span class="error"><?php echo $websiteErr; ?></span>
|
||||
<br><br>
|
||||
|
||||
Comment: <textarea name="comment" rows="5" cols="40"></textarea>
|
||||
<br><br>
|
||||
|
||||
Gender:
|
||||
<input type="radio" name="gender" value="female">Female
|
||||
<input type="radio" name="gender" value="male">Male
|
||||
<input type="radio" name="gender" value="other">Other
|
||||
<span class="error">* <?php echo $genderErr; ?></span>
|
||||
<br><br>
|
||||
|
||||
<input type="submit" name="submit" value="Submit">
|
||||
|
||||
</form>
|
||||
```
|
||||
|
||||
### Styling Error Messages
|
||||
|
||||
Use CSS to make error messages stand out:
|
||||
|
||||
```css
|
||||
.error {
|
||||
color: #FF0000;
|
||||
}
|
||||
```
|
||||
|
||||
### Required Field Indicators
|
||||
|
||||
It is common to place an asterisk `*` next to required fields to indicate they must be filled out. The asterisk can be added directly in the HTML or dynamically with PHP.
|
||||
|
||||
---
|
||||
|
||||
## PHP Form URL and Email Validation
|
||||
|
||||
> **Source:** <https://www.w3schools.com/php/php_form_url_email.asp>
|
||||
|
||||
### Validating a Name
|
||||
|
||||
Check that the name field only contains letters, dashes, apostrophes, and whitespace using `preg_match()`:
|
||||
|
||||
```php
|
||||
$name = test_input($_POST["name"]);
|
||||
if (!preg_match("/^[a-zA-Z-' ]*$/", $name)) {
|
||||
$nameErr = "Only letters and white space allowed";
|
||||
}
|
||||
```
|
||||
|
||||
The `preg_match()` function searches a string for a pattern, returning `1` if the pattern was found and `0` if not.
|
||||
|
||||
### Validating an E-mail Address
|
||||
|
||||
Check that an e-mail address is well-formed using `filter_var()`:
|
||||
|
||||
```php
|
||||
$email = test_input($_POST["email"]);
|
||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$emailErr = "Invalid email format";
|
||||
}
|
||||
```
|
||||
|
||||
The `filter_var()` function filters a variable with the specified filter. `FILTER_VALIDATE_EMAIL` validates whether the value is a valid email address.
|
||||
|
||||
### Validating a URL
|
||||
|
||||
Check that a URL is valid using `preg_match()`:
|
||||
|
||||
```php
|
||||
$website = test_input($_POST["website"]);
|
||||
if (!preg_match("/\b(?:https?|ftp):\/\/|www\.[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i", $website)) {
|
||||
$websiteErr = "Invalid URL";
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, `filter_var()` can also validate URLs:
|
||||
|
||||
```php
|
||||
if (!filter_var($website, FILTER_VALIDATE_URL)) {
|
||||
$websiteErr = "Invalid URL";
|
||||
}
|
||||
```
|
||||
|
||||
### Combined Validation Logic
|
||||
|
||||
Incorporate all validation checks within the form processing block:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$nameErr = $emailErr = $genderErr = $websiteErr = "";
|
||||
$name = $email = $gender = $comment = $website = "";
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
if (empty($_POST["name"])) {
|
||||
$nameErr = "Name is required";
|
||||
} else {
|
||||
$name = test_input($_POST["name"]);
|
||||
if (!preg_match("/^[a-zA-Z-' ]*$/", $name)) {
|
||||
$nameErr = "Only letters and white space allowed";
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($_POST["email"])) {
|
||||
$emailErr = "Email is required";
|
||||
} else {
|
||||
$email = test_input($_POST["email"]);
|
||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$emailErr = "Invalid email format";
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($_POST["website"])) {
|
||||
$website = "";
|
||||
} else {
|
||||
$website = test_input($_POST["website"]);
|
||||
if (!preg_match("/\b(?:https?|ftp):\/\/|www\.[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i", $website)) {
|
||||
$websiteErr = "Invalid URL";
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($_POST["comment"])) {
|
||||
$comment = "";
|
||||
} else {
|
||||
$comment = test_input($_POST["comment"]);
|
||||
}
|
||||
|
||||
if (empty($_POST["gender"])) {
|
||||
$genderErr = "Gender is required";
|
||||
} else {
|
||||
$gender = test_input($_POST["gender"]);
|
||||
}
|
||||
}
|
||||
?>
|
||||
```
|
||||
|
||||
### PHP Validation Functions Reference
|
||||
|
||||
| Function | Purpose |
|
||||
|----------|---------|
|
||||
| `preg_match(pattern, string)` | Tests whether a string matches a regular expression pattern. Returns `1` if matched, `0` if not. |
|
||||
| `filter_var(value, filter)` | Filters a variable with a specified filter constant. Returns the filtered data on success, or `false` on failure. |
|
||||
| `FILTER_VALIDATE_EMAIL` | Filter constant that validates an email address format. |
|
||||
| `FILTER_VALIDATE_URL` | Filter constant that validates a URL format. |
|
||||
|
||||
---
|
||||
|
||||
## PHP Complete Form Example
|
||||
|
||||
> **Source:** <https://www.w3schools.com/php/php_form_complete.asp>
|
||||
|
||||
### Retaining Form Values After Submission
|
||||
|
||||
To show the values in the input fields after the user hits the submit button, add a small PHP script inside the `value` attribute of each input element and inside the textarea element. This way, the form retains the user's entered data even when validation errors occur.
|
||||
|
||||
Use `<?php echo $variable; ?>` to output the value:
|
||||
|
||||
```html
|
||||
Name: <input type="text" name="name" value="<?php echo $name; ?>">
|
||||
|
||||
E-mail: <input type="text" name="email" value="<?php echo $email; ?>">
|
||||
|
||||
Website: <input type="text" name="website" value="<?php echo $website; ?>">
|
||||
|
||||
Comment: <textarea name="comment" rows="5" cols="40"><?php echo $comment; ?></textarea>
|
||||
```
|
||||
|
||||
### Retaining Radio Button Selection
|
||||
|
||||
For radio buttons, check whether the value was previously selected using a conditional:
|
||||
|
||||
```html
|
||||
Gender:
|
||||
<input type="radio" name="gender"
|
||||
<?php if (isset($gender) && $gender == "female") echo "checked"; ?>
|
||||
value="female">Female
|
||||
|
||||
<input type="radio" name="gender"
|
||||
<?php if (isset($gender) && $gender == "male") echo "checked"; ?>
|
||||
value="male">Male
|
||||
|
||||
<input type="radio" name="gender"
|
||||
<?php if (isset($gender) && $gender == "other") echo "checked"; ?>
|
||||
value="other">Other
|
||||
```
|
||||
|
||||
### The Complete PHP Form Script
|
||||
|
||||
```php
|
||||
<?php
|
||||
// Define variables and set to empty values
|
||||
$nameErr = $emailErr = $genderErr = $websiteErr = "";
|
||||
$name = $email = $gender = $comment = $website = "";
|
||||
|
||||
function test_input($data) {
|
||||
$data = trim($data);
|
||||
$data = stripslashes($data);
|
||||
$data = htmlspecialchars($data);
|
||||
return $data;
|
||||
}
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
if (empty($_POST["name"])) {
|
||||
$nameErr = "Name is required";
|
||||
} else {
|
||||
$name = test_input($_POST["name"]);
|
||||
// Check if name only contains letters and whitespace
|
||||
if (!preg_match("/^[a-zA-Z-' ]*$/", $name)) {
|
||||
$nameErr = "Only letters and white space allowed";
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($_POST["email"])) {
|
||||
$emailErr = "Email is required";
|
||||
} else {
|
||||
$email = test_input($_POST["email"]);
|
||||
// Check if e-mail address is well-formed
|
||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$emailErr = "Invalid email format";
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($_POST["website"])) {
|
||||
$website = "";
|
||||
} else {
|
||||
$website = test_input($_POST["website"]);
|
||||
// Check if URL address syntax is valid
|
||||
if (!preg_match("/\b(?:https?|ftp):\/\/|www\.[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i", $website)) {
|
||||
$websiteErr = "Invalid URL";
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($_POST["comment"])) {
|
||||
$comment = "";
|
||||
} else {
|
||||
$comment = test_input($_POST["comment"]);
|
||||
}
|
||||
|
||||
if (empty($_POST["gender"])) {
|
||||
$genderErr = "Gender is required";
|
||||
} else {
|
||||
$gender = test_input($_POST["gender"]);
|
||||
}
|
||||
}
|
||||
?>
|
||||
```
|
||||
|
||||
### The Complete HTML Form
|
||||
|
||||
```html
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
.error {color: #FF0000;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h2>PHP Form Validation Example</h2>
|
||||
<p><span class="error">* required field</span></p>
|
||||
|
||||
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>">
|
||||
|
||||
Name: <input type="text" name="name" value="<?php echo $name; ?>">
|
||||
<span class="error">* <?php echo $nameErr; ?></span>
|
||||
<br><br>
|
||||
|
||||
E-mail: <input type="text" name="email" value="<?php echo $email; ?>">
|
||||
<span class="error">* <?php echo $emailErr; ?></span>
|
||||
<br><br>
|
||||
|
||||
Website: <input type="text" name="website" value="<?php echo $website; ?>">
|
||||
<span class="error"><?php echo $websiteErr; ?></span>
|
||||
<br><br>
|
||||
|
||||
Comment: <textarea name="comment" rows="5" cols="40"><?php echo $comment; ?></textarea>
|
||||
<br><br>
|
||||
|
||||
Gender:
|
||||
<input type="radio" name="gender"
|
||||
<?php if (isset($gender) && $gender == "female") echo "checked"; ?>
|
||||
value="female">Female
|
||||
<input type="radio" name="gender"
|
||||
<?php if (isset($gender) && $gender == "male") echo "checked"; ?>
|
||||
value="male">Male
|
||||
<input type="radio" name="gender"
|
||||
<?php if (isset($gender) && $gender == "other") echo "checked"; ?>
|
||||
value="other">Other
|
||||
<span class="error">* <?php echo $genderErr; ?></span>
|
||||
<br><br>
|
||||
|
||||
<input type="submit" name="submit" value="Submit">
|
||||
|
||||
</form>
|
||||
|
||||
<?php
|
||||
echo "<h2>Your Input:</h2>";
|
||||
echo $name;
|
||||
echo "<br>";
|
||||
echo $email;
|
||||
echo "<br>";
|
||||
echo $website;
|
||||
echo "<br>";
|
||||
echo $comment;
|
||||
echo "<br>";
|
||||
echo $gender;
|
||||
?>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### Summary of Key Functions
|
||||
|
||||
| Function | Purpose |
|
||||
|----------|---------|
|
||||
| `htmlspecialchars()` | Converts special characters (`<`, `>`, `&`, `"`, `'`) to HTML entities to prevent XSS |
|
||||
| `trim()` | Strips whitespace (or other characters) from the beginning and end of a string |
|
||||
| `stripslashes()` | Removes backslashes from a string |
|
||||
| `empty()` | Checks whether a variable is empty, null, or falsy |
|
||||
| `isset()` | Checks whether a variable is set and is not null |
|
||||
| `preg_match()` | Performs a regular expression match on a string |
|
||||
| `filter_var()` | Filters a variable with a specified filter |
|
||||
| `$_POST` | Superglobal array that collects form data sent with the POST method |
|
||||
| `$_GET` | Superglobal array that collects form data sent with the GET method |
|
||||
| `$_SERVER["PHP_SELF"]` | Returns the filename of the currently executing script |
|
||||
| `$_SERVER["REQUEST_METHOD"]` | Returns the request method used to access the page (e.g., `POST`, `GET`) |
|
||||
|
||||
### Key Takeaways
|
||||
|
||||
1. **Always sanitize user input** using `trim()`, `stripslashes()`, and `htmlspecialchars()` via a reusable `test_input()` function.
|
||||
2. **Protect against XSS** by passing `$_SERVER["PHP_SELF"]` through `htmlspecialchars()` in the form action attribute.
|
||||
3. **Use `$_SERVER["REQUEST_METHOD"]`** to check if the form was submitted before processing.
|
||||
4. **Validate required fields** with `empty()` and display error messages next to each field.
|
||||
5. **Validate data formats** using `preg_match()` for patterns (names, URLs) and `filter_var()` for emails and URLs.
|
||||
6. **Retain form values** after submission by echoing variables back into input `value` attributes and textarea content.
|
||||
7. **Retain radio button state** by conditionally adding the `checked` attribute using `isset()` and value comparison.
|
||||
8. **POST is preferred** over GET for form submissions that contain sensitive or large amounts of data.
|
||||
202
skills/create-web-form/references/php-json.md
Normal file
202
skills/create-web-form/references/php-json.md
Normal file
@@ -0,0 +1,202 @@
|
||||
# PHP JSON Reference
|
||||
|
||||
> Source: <https://www.w3schools.com/php/php_json.asp>
|
||||
|
||||
## What is JSON?
|
||||
|
||||
JSON stands for **JavaScript Object Notation** and is a syntax for storing and exchanging data. JSON is a text format that is completely language independent. Since the JSON format is text only, it can easily be sent to and from a server, and used as a data format by any programming language.
|
||||
|
||||
PHP has some built-in functions to handle JSON:
|
||||
|
||||
- `json_encode()` -- Encodes a value to JSON format
|
||||
- `json_decode()` -- Decodes a JSON string into a PHP variable
|
||||
|
||||
## `json_encode()` -- Encoding PHP to JSON
|
||||
|
||||
The `json_encode()` function is used to encode a value to JSON format (a valid JSON string).
|
||||
|
||||
### Encoding an Associative Array
|
||||
|
||||
```php
|
||||
<?php
|
||||
$age = array("Peter" => 35, "Ben" => 37, "Joe" => 43);
|
||||
|
||||
echo json_encode($age);
|
||||
?>
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
{"Peter":35,"Ben":37,"Joe":43}
|
||||
```
|
||||
|
||||
### Encoding an Indexed Array
|
||||
|
||||
```php
|
||||
<?php
|
||||
$cars = array("Volvo", "BMW", "Toyota");
|
||||
|
||||
echo json_encode($cars);
|
||||
?>
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
["Volvo","BMW","Toyota"]
|
||||
```
|
||||
|
||||
### Encoding a PHP Object
|
||||
|
||||
```php
|
||||
<?php
|
||||
$myObj = new stdClass();
|
||||
$myObj->name = "John";
|
||||
$myObj->age = 30;
|
||||
$myObj->city = "New York";
|
||||
|
||||
echo json_encode($myObj);
|
||||
?>
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```json
|
||||
{"name":"John","age":30,"city":"New York"}
|
||||
```
|
||||
|
||||
## `json_decode()` -- Decoding JSON to PHP
|
||||
|
||||
The `json_decode()` function is used to decode a JSON string into a PHP object or associative array.
|
||||
|
||||
### Syntax
|
||||
|
||||
```php
|
||||
json_decode(string, assoc, depth, options)
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------|---------------------------------------------------------------------------------------------------------------|
|
||||
| `string` | Required. Specifies the JSON string to be decoded. |
|
||||
| `assoc` | Optional. If set to `true`, the returned object will be converted into an associative array. Default is `false`. |
|
||||
| `depth` | Optional. Specifies the maximum recursion depth. Default is `512`. |
|
||||
| `options` | Optional. Specifies a bitmask (e.g., `JSON_BIGINT_AS_STRING`). |
|
||||
|
||||
### Decoding JSON into a PHP Object (default)
|
||||
|
||||
By default, the `json_decode()` function returns an object:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$jsonobj = '{"Peter":35,"Ben":37,"Joe":43}';
|
||||
|
||||
$obj = json_decode($jsonobj);
|
||||
|
||||
echo $obj->Peter; // Outputs: 35
|
||||
echo $obj->Ben; // Outputs: 37
|
||||
echo $obj->Joe; // Outputs: 43
|
||||
?>
|
||||
```
|
||||
|
||||
### Decoding JSON into an Associative Array
|
||||
|
||||
When the second parameter is set to `true`, the JSON string is decoded into an associative array:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$jsonobj = '{"Peter":35,"Ben":37,"Joe":43}';
|
||||
|
||||
$arr = json_decode($jsonobj, true);
|
||||
|
||||
echo $arr["Peter"]; // Outputs: 35
|
||||
echo $arr["Ben"]; // Outputs: 37
|
||||
echo $arr["Joe"]; // Outputs: 43
|
||||
?>
|
||||
```
|
||||
|
||||
## Accessing Decoded Values
|
||||
|
||||
### From an Object
|
||||
|
||||
Use the arrow (`->`) operator to access values from a decoded object:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$jsonobj = '{"Peter":35,"Ben":37,"Joe":43}';
|
||||
|
||||
$obj = json_decode($jsonobj);
|
||||
|
||||
echo $obj->Peter;
|
||||
echo $obj->Ben;
|
||||
echo $obj->Joe;
|
||||
?>
|
||||
```
|
||||
|
||||
### From an Associative Array
|
||||
|
||||
Use square bracket syntax to access values from a decoded associative array:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$jsonobj = '{"Peter":35,"Ben":37,"Joe":43}';
|
||||
|
||||
$arr = json_decode($jsonobj, true);
|
||||
|
||||
echo $arr["Peter"];
|
||||
echo $arr["Ben"];
|
||||
echo $arr["Joe"];
|
||||
?>
|
||||
```
|
||||
|
||||
## Looping Through Values
|
||||
|
||||
### Looping Through an Object
|
||||
|
||||
Use a `foreach` loop to loop through the values of a decoded object:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$jsonobj = '{"Peter":35,"Ben":37,"Joe":43}';
|
||||
|
||||
$obj = json_decode($jsonobj);
|
||||
|
||||
foreach($obj as $key => $value) {
|
||||
echo $key . " => " . $value . "<br>";
|
||||
}
|
||||
?>
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
Peter => 35
|
||||
Ben => 37
|
||||
Joe => 43
|
||||
```
|
||||
|
||||
### Looping Through an Associative Array
|
||||
|
||||
Use a `foreach` loop to loop through the values of a decoded associative array:
|
||||
|
||||
```php
|
||||
<?php
|
||||
$jsonobj = '{"Peter":35,"Ben":37,"Joe":43}';
|
||||
|
||||
$arr = json_decode($jsonobj, true);
|
||||
|
||||
foreach($arr as $key => $value) {
|
||||
echo $key . " => " . $value . "<br>";
|
||||
}
|
||||
?>
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
Peter => 35
|
||||
Ben => 37
|
||||
Joe => 43
|
||||
```
|
||||
1696
skills/create-web-form/references/php-mysql-database.md
Normal file
1696
skills/create-web-form/references/php-mysql-database.md
Normal file
File diff suppressed because it is too large
Load Diff
211
skills/create-web-form/references/progressive-web-app.md
Normal file
211
skills/create-web-form/references/progressive-web-app.md
Normal file
@@ -0,0 +1,211 @@
|
||||
# Progressive Web App Reference
|
||||
|
||||
---
|
||||
|
||||
## Overview: What Are Progressive Web Apps?
|
||||
|
||||
> Source: <https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps>
|
||||
|
||||
A **Progressive Web App (PWA)** is an app built using web platform technologies that provides a user experience comparable to a platform-specific (native) app. Key characteristics include:
|
||||
|
||||
- Runs on multiple platforms and devices from a single codebase
|
||||
- Can be installed on devices like native apps
|
||||
- Operates offline and in the background
|
||||
- Integrates with device features and other installed apps
|
||||
- Appears as a permanent feature users can launch directly from the OS
|
||||
|
||||
### Main Guides
|
||||
|
||||
| Guide | Description |
|
||||
|-------|-------------|
|
||||
| **What is a Progressive Web App?** | Comparison with traditional websites and platform-specific apps; introduction to main PWA features |
|
||||
| **Making PWAs Installable** | Requirements for installability, device installation process, customizing the install experience |
|
||||
| **Installing and Uninstalling Web Apps** | How users install and uninstall PWAs on their devices |
|
||||
| **Offline and Background Operation** | Technologies enabling offline functionality, intermittent network connectivity management, background task execution |
|
||||
| **Caching** | APIs for local resource caching, common caching strategies for offline functionality |
|
||||
| **Best Practices for PWAs** | Cross-browser and device adaptation, accessibility, performance optimization, OS integration |
|
||||
|
||||
### How-To Implementation Features
|
||||
|
||||
| Feature | Purpose |
|
||||
|---------|---------|
|
||||
| Create a standalone app | Launch in a dedicated window instead of a browser tab |
|
||||
| Define app icons | Customize icons for the installed PWA |
|
||||
| Customize app colors | Set background and theme colors |
|
||||
| Display badges | Show badges on the app icon (e.g., notification counts) |
|
||||
| Expose app shortcuts | Access common actions from the OS shortcut menu |
|
||||
| Share data between apps | Use OS app-sharing mechanisms |
|
||||
| Trigger installation | Provide custom UI to invite user installation |
|
||||
| Associate files | Connect file types to the PWA for handling |
|
||||
|
||||
### Core Technologies and APIs
|
||||
|
||||
#### Web App Manifest
|
||||
|
||||
- Defines PWA metadata and appearance
|
||||
- Customizes deep OS integration (name, icons, display mode, colors, etc.)
|
||||
|
||||
#### Service Worker APIs
|
||||
|
||||
**Communication:**
|
||||
|
||||
- `Client.postMessage()` -- Service worker to PWA messaging
|
||||
- Broadcast Channel API -- Two-way communication between service worker and client
|
||||
|
||||
**Offline Operation:**
|
||||
|
||||
- `Cache` API -- Persistent HTTP response storage
|
||||
- `Clients` -- Document access control for service-worker-controlled documents
|
||||
- `FetchEvent` -- HTTP request interception and caching
|
||||
|
||||
**Background Tasks:**
|
||||
|
||||
- Background Synchronization API -- Defer tasks until a stable network connection
|
||||
- Web Periodic Background Synchronization API -- Register periodic tasks with network connectivity
|
||||
- Background Fetch API -- Manage large, long-duration downloads
|
||||
|
||||
#### Other Essential Web APIs
|
||||
|
||||
| API | Purpose |
|
||||
|-----|---------|
|
||||
| **IndexedDB** | Client-side storage for structured data and files |
|
||||
| **Badging API** | Application icon badge notifications |
|
||||
| **Notifications API** | OS-level notification display |
|
||||
| **Web Share API** | Share content to user-selected apps |
|
||||
| **Window Controls Overlay API** | Desktop PWA window customization (hide title bar, display app over full window) |
|
||||
|
||||
### Essential PWA Checklist
|
||||
|
||||
- Installable and standalone operation
|
||||
- Offline functionality via service workers
|
||||
- Caching strategies implemented
|
||||
- Web app manifest configured
|
||||
- App icons and colors defined
|
||||
- Accessible and performant
|
||||
- Cross-browser compatible
|
||||
- Secure (HTTPS required)
|
||||
|
||||
---
|
||||
|
||||
## Tutorials
|
||||
|
||||
> Source: <https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Tutorials>
|
||||
|
||||
These tutorials provide structured, step-by-step learning paths for building PWAs from start to finish.
|
||||
|
||||
### Tutorial 1: CycleTracker -- Creating Your First PWA
|
||||
|
||||
**Level:** Novice
|
||||
|
||||
A menstrual cycle tracking app that walks through the complete process of turning a web app into a PWA.
|
||||
|
||||
**Sub-modules:**
|
||||
|
||||
1. **Base HTML and CSS** -- Build the foundational web app structure
|
||||
2. **Secure connection** -- Set up a testing environment with HTTPS
|
||||
3. **JavaScript functionality** -- Add interactivity and application logic
|
||||
4. **Manifest and iconography** -- Create and inspect a web app manifest; define icons
|
||||
5. **Offline support using service workers** -- Add service workers and manage stale caches
|
||||
|
||||
**Topics Covered:**
|
||||
|
||||
- HTML, CSS, and JavaScript fundamentals for creating a functional web app
|
||||
- Setting up a testing environment
|
||||
- Upgrading a web app into a PWA
|
||||
- Manifest development: creating and inspecting a web app manifest
|
||||
- Service workers: adding service workers to the application
|
||||
- Cache management: using service workers to delete stale caches
|
||||
|
||||
### Tutorial 2: js13kGames -- Deep Dive into PWA
|
||||
|
||||
**Level:** Intermediate
|
||||
|
||||
A game information listing app (from the js13kGames 2017 competition) that explores advanced PWA features.
|
||||
|
||||
**Sub-modules:**
|
||||
|
||||
1. **PWA structure** -- Understand app architecture and organization
|
||||
2. **Offline support using service workers** -- Implement offline functionality
|
||||
3. **Making PWAs installable** -- Meet installability requirements
|
||||
4. **Using Notifications and Push APIs** -- Implement push notifications
|
||||
5. **Progressive loading** -- Optimize loading performance
|
||||
|
||||
**Topics Covered:**
|
||||
|
||||
- PWA basics and core concepts
|
||||
- Notifications and Push APIs: implementing notifications and push functionality
|
||||
- App performance: optimizing PWA performance
|
||||
- Advanced PWA features beyond the basics
|
||||
|
||||
---
|
||||
|
||||
## API and Manifest Reference
|
||||
|
||||
> Source: <https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Reference>
|
||||
|
||||
### Web App Manifest Members
|
||||
|
||||
The web app manifest describes PWA characteristics, customizes its appearance, and enables deeper OS integration. The following members can be defined in the manifest JSON file:
|
||||
|
||||
| Member | Status | Description |
|
||||
|--------|--------|-------------|
|
||||
| `name` | Standard | Full name of the application |
|
||||
| `short_name` | Standard | Short name for limited-space contexts |
|
||||
| `description` | Standard | Description of the application |
|
||||
| `start_url` | Standard | URL that loads when the app is launched |
|
||||
| `scope` | Standard | Navigation scope of the PWA |
|
||||
| `display` | Standard | Display mode (fullscreen, standalone, minimal-ui, browser) |
|
||||
| `display_override` | Experimental | Override display mode preferences |
|
||||
| `orientation` | Standard | Default orientation for the app |
|
||||
| `icons` | Standard | Array of icon objects for various contexts |
|
||||
| `screenshots` | Standard | Screenshots for app stores and install UI |
|
||||
| `background_color` | Standard | Background color for the splash screen |
|
||||
| `theme_color` | Standard | Default theme color for the application |
|
||||
| `categories` | Standard | Expected application categories |
|
||||
| `id` | Standard | Unique identifier for the application |
|
||||
| `shortcuts` | Standard | Quick-access shortcuts to key tasks |
|
||||
| `file_handlers` | Experimental | File types the app can handle |
|
||||
| `launch_handler` | Experimental | Control how the app is launched |
|
||||
| `protocol_handlers` | Experimental | URL protocols the app can handle |
|
||||
| `share_target` | Experimental | Define how the app receives shared data |
|
||||
| `scope_extensions` | Experimental | Extend the navigation scope |
|
||||
| `note_taking` | Experimental | Note-taking app integration |
|
||||
| `related_applications` | Experimental | Related native applications |
|
||||
| `prefer_related_applications` | Experimental | Prefer native app over PWA |
|
||||
| `serviceworker` | Experimental / Non-standard | Service worker registration info |
|
||||
|
||||
### Service Worker APIs
|
||||
|
||||
#### Communication with the App
|
||||
|
||||
- **`Client.postMessage()`** -- Send messages from the service worker to client pages
|
||||
- **Broadcast Channel API** -- Create a two-way communication channel between the service worker and the client PWA
|
||||
|
||||
#### Offline Operation
|
||||
|
||||
- **`Cache`** -- Persistent storage of HTTP responses for reuse when offline
|
||||
- **`Clients`** -- Interface to access service-worker-controlled documents
|
||||
- **`FetchEvent`** -- Intercept HTTP requests; enables caching or proxying responses for offline support
|
||||
|
||||
#### Background Operation
|
||||
|
||||
- **Background Synchronization API** -- Defer tasks until the network connection is stable
|
||||
- **Web Periodic Background Synchronization API** -- Register periodic tasks that run with network connectivity
|
||||
- **Background Fetch API** -- Manage long-duration downloads such as video and audio files
|
||||
|
||||
### Other Web APIs for PWAs
|
||||
|
||||
| API | Purpose |
|
||||
|-----|---------|
|
||||
| **IndexedDB** | Client-side storage for structured data and files |
|
||||
| **Badging API** | Set application icon badges for notification indicators |
|
||||
| **Notifications API** | Display OS-level system notifications |
|
||||
| **Web Share API** | Share text, links, files, and content to user-selected apps |
|
||||
| **Window Controls Overlay API** | Hide the title bar and display the app over the full window area (desktop PWAs) |
|
||||
|
||||
### Key MDN Reference Paths
|
||||
|
||||
- **Main PWA Index:** `/en-US/docs/Web/Progressive_web_apps`
|
||||
- **Service Worker API:** `/en-US/docs/Web/API/Service_Worker_API`
|
||||
- **Web APIs Overview:** `/en-US/docs/Web/API`
|
||||
- **Web App Manifest:** `/en-US/docs/Web/Progressive_web_apps/Manifest`
|
||||
567
skills/create-web-form/references/python-as-web-framework.md
Normal file
567
skills/create-web-form/references/python-as-web-framework.md
Normal file
@@ -0,0 +1,567 @@
|
||||
# Python as Web Framework Reference
|
||||
|
||||
> Source: <https://www.topcoder.com/thrive/articles/python-as-web-framework-the-flask-basics>
|
||||
|
||||
This reference covers using Python as a web framework through Flask, including setup, routing, templates, request and response handling, form processing, and building practical web applications.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Flask is a lightweight **WSGI** (Web Server Gateway Interface) web framework written in Python. It is classified as a micro-framework because it does not require particular tools or libraries. Flask has no database abstraction layer, form validation, or any other components where pre-existing third-party libraries provide common functions.
|
||||
|
||||
### Why Flask?
|
||||
|
||||
- **Lightweight and modular** -- only includes what you need
|
||||
- **Easy to learn** -- minimal boilerplate to get started
|
||||
- **Flexible** -- no enforced project structure or dependencies
|
||||
- **Extensible** -- rich ecosystem of extensions for added functionality
|
||||
- **Well-documented** with an active community
|
||||
- **Built-in development server** and debugger
|
||||
|
||||
---
|
||||
|
||||
## Installation and Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Python 3.7+
|
||||
- pip (Python package manager)
|
||||
|
||||
### Install Flask
|
||||
|
||||
```bash
|
||||
pip install flask
|
||||
```
|
||||
|
||||
### Verify Installation
|
||||
|
||||
```python
|
||||
import flask
|
||||
print(flask.__version__)
|
||||
```
|
||||
|
||||
### Virtual Environment (Recommended)
|
||||
|
||||
```bash
|
||||
# Create a virtual environment
|
||||
python -m venv venv
|
||||
|
||||
# Activate (Linux/macOS)
|
||||
source venv/bin/activate
|
||||
|
||||
# Activate (Windows)
|
||||
venv\Scripts\activate
|
||||
|
||||
# Install Flask in the virtual environment
|
||||
pip install flask
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Creating a Basic Flask Application
|
||||
|
||||
### Hello World
|
||||
|
||||
```python
|
||||
from flask import Flask
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route('/')
|
||||
def hello_world():
|
||||
return '<h1>Hello, World!</h1>'
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
||||
```
|
||||
|
||||
### Understanding the Code
|
||||
|
||||
| Component | Purpose |
|
||||
|-----------|---------|
|
||||
| `Flask(__name__)` | Creates a Flask application instance; `__name__` helps Flask locate resources |
|
||||
| `@app.route('/')` | A decorator that maps a URL path to a Python function |
|
||||
| `app.run(debug=True)` | Starts the development server with auto-reload and debugger |
|
||||
|
||||
### Running the Application
|
||||
|
||||
```bash
|
||||
python app.py
|
||||
```
|
||||
|
||||
The application runs at `http://127.0.0.1:5000/` by default.
|
||||
|
||||
### Debug Mode
|
||||
|
||||
Debug mode provides:
|
||||
|
||||
- **Auto-reloader** -- restarts the server when code changes
|
||||
- **Interactive debugger** -- shows a traceback in the browser with an interactive Python console
|
||||
- **Detailed error pages** -- shows full error details instead of generic "500 Internal Server Error"
|
||||
|
||||
**Warning:** Never enable debug mode in production -- it allows arbitrary code execution.
|
||||
|
||||
---
|
||||
|
||||
## Routing
|
||||
|
||||
### Basic Routes
|
||||
|
||||
```python
|
||||
@app.route('/')
|
||||
def index():
|
||||
return 'Index Page'
|
||||
|
||||
@app.route('/hello')
|
||||
def hello():
|
||||
return 'Hello, World!'
|
||||
|
||||
@app.route('/about')
|
||||
def about():
|
||||
return 'About Page'
|
||||
```
|
||||
|
||||
### Variable Rules (Dynamic URLs)
|
||||
|
||||
```python
|
||||
@app.route('/user/<username>')
|
||||
def show_user_profile(username):
|
||||
return f'User: {username}'
|
||||
|
||||
@app.route('/post/<int:post_id>')
|
||||
def show_post(post_id):
|
||||
return f'Post {post_id}'
|
||||
|
||||
@app.route('/path/<path:subpath>')
|
||||
def show_subpath(subpath):
|
||||
return f'Subpath: {subpath}'
|
||||
```
|
||||
|
||||
### URL Converters
|
||||
|
||||
| Converter | Description | Example |
|
||||
|-----------|-------------|---------|
|
||||
| `string` | Accepts any text without slashes (default) | `/user/<username>` |
|
||||
| `int` | Accepts positive integers | `/post/<int:post_id>` |
|
||||
| `float` | Accepts positive floating-point values | `/price/<float:amount>` |
|
||||
| `path` | Accepts text including slashes | `/file/<path:filepath>` |
|
||||
| `uuid` | Accepts UUID strings | `/item/<uuid:item_id>` |
|
||||
|
||||
### URL Building with `url_for()`
|
||||
|
||||
```python
|
||||
from flask import url_for
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return 'Index'
|
||||
|
||||
@app.route('/login')
|
||||
def login():
|
||||
return 'Login'
|
||||
|
||||
@app.route('/user/<username>')
|
||||
def profile(username):
|
||||
return f'{username} profile'
|
||||
|
||||
# Usage:
|
||||
with app.test_request_context():
|
||||
print(url_for('index')) # /
|
||||
print(url_for('login')) # /login
|
||||
print(url_for('profile', username='John')) # /user/John
|
||||
```
|
||||
|
||||
### HTTP Methods
|
||||
|
||||
```python
|
||||
from flask import request
|
||||
|
||||
@app.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
if request.method == 'POST':
|
||||
return do_the_login()
|
||||
else:
|
||||
return show_the_login_form()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Templates with Jinja2
|
||||
|
||||
Flask uses the Jinja2 template engine for rendering HTML.
|
||||
|
||||
### Rendering Templates
|
||||
|
||||
```python
|
||||
from flask import render_template
|
||||
|
||||
@app.route('/hello/')
|
||||
@app.route('/hello/<name>')
|
||||
def hello(name=None):
|
||||
return render_template('hello.html', name=name)
|
||||
```
|
||||
|
||||
### Template File (`templates/hello.html`)
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Hello</title>
|
||||
</head>
|
||||
<body>
|
||||
{% if name %}
|
||||
<h1>Hello, {{ name }}!</h1>
|
||||
{% else %}
|
||||
<h1>Hello, World!</h1>
|
||||
{% endif %}
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### Template Syntax
|
||||
|
||||
| Syntax | Purpose | Example |
|
||||
|--------|---------|---------|
|
||||
| `{{ ... }}` | Expression output | `{{ user.name }}` |
|
||||
| `{% ... %}` | Statement (control flow) | `{% if user %}...{% endif %}` |
|
||||
| `{# ... #}` | Comment (not rendered) | `{# This is a comment #}` |
|
||||
|
||||
### Template Inheritance
|
||||
|
||||
**Base template (`base.html`):**
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{% block title %}Default Title{% endblock %}</title>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
{% block header %}
|
||||
<h1>My Website</h1>
|
||||
{% endblock %}
|
||||
</header>
|
||||
|
||||
<main>
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
{% block footer %}
|
||||
<p>Footer content</p>
|
||||
{% endblock %}
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
**Child template (`home.html`):**
|
||||
|
||||
```html
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Home Page{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Welcome!</h2>
|
||||
<p>This is the home page.</p>
|
||||
{% endblock %}
|
||||
```
|
||||
|
||||
### Loops and Conditionals
|
||||
|
||||
```html
|
||||
<!-- For loop -->
|
||||
<ul>
|
||||
{% for item in navigation %}
|
||||
<li><a href="{{ item.href }}">{{ item.caption }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<!-- Conditionals -->
|
||||
{% if users %}
|
||||
<ul>
|
||||
{% for user in users %}
|
||||
<li>{{ user.username }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p>No users found.</p>
|
||||
{% endif %}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Request and Response
|
||||
|
||||
### The Request Object
|
||||
|
||||
```python
|
||||
from flask import request
|
||||
|
||||
@app.route('/login', methods=['POST', 'GET'])
|
||||
def login():
|
||||
error = None
|
||||
if request.method == 'POST':
|
||||
username = request.form['username']
|
||||
password = request.form['password']
|
||||
|
||||
if valid_login(username, password):
|
||||
return log_the_user_in(username)
|
||||
else:
|
||||
error = 'Invalid username/password'
|
||||
|
||||
return render_template('login.html', error=error)
|
||||
```
|
||||
|
||||
### Request Object Attributes
|
||||
|
||||
| Attribute | Description |
|
||||
|-----------|-------------|
|
||||
| `request.method` | The HTTP method (GET, POST, etc.) |
|
||||
| `request.form` | Form data from POST/PUT requests |
|
||||
| `request.args` | URL query string parameters |
|
||||
| `request.files` | Uploaded files |
|
||||
| `request.cookies` | Request cookies |
|
||||
| `request.headers` | Request headers |
|
||||
| `request.json` | Parsed JSON data (if content type is JSON) |
|
||||
| `request.data` | Raw request data as bytes |
|
||||
| `request.url` | The full URL of the request |
|
||||
| `request.path` | The URL path (without query string) |
|
||||
|
||||
### Query String Parameters
|
||||
|
||||
```python
|
||||
# URL: /search?q=flask&page=2
|
||||
@app.route('/search')
|
||||
def search():
|
||||
query = request.args.get('q', '')
|
||||
page = request.args.get('page', 1, type=int)
|
||||
return f'Searching for: {query}, Page: {page}'
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
```python
|
||||
from flask import make_response, jsonify
|
||||
|
||||
# Simple string response
|
||||
@app.route('/')
|
||||
def index():
|
||||
return 'Hello World'
|
||||
|
||||
# Response with status code
|
||||
@app.route('/not-found')
|
||||
def not_found():
|
||||
return 'Page Not Found', 404
|
||||
|
||||
# Custom response object
|
||||
@app.route('/custom')
|
||||
def custom():
|
||||
response = make_response('Custom Response')
|
||||
response.headers['X-Custom-Header'] = 'custom-value'
|
||||
return response
|
||||
|
||||
# JSON response
|
||||
@app.route('/api/data')
|
||||
def api_data():
|
||||
return jsonify({'name': 'Flask', 'version': '2.0'})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Form Handling
|
||||
|
||||
### HTML Form
|
||||
|
||||
```html
|
||||
<form method="POST" action="/submit">
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" id="name" name="name" required>
|
||||
|
||||
<label for="email">Email:</label>
|
||||
<input type="email" id="email" name="email" required>
|
||||
|
||||
<label for="message">Message:</label>
|
||||
<textarea id="message" name="message" required></textarea>
|
||||
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
```
|
||||
|
||||
### Processing Form Data
|
||||
|
||||
```python
|
||||
@app.route('/submit', methods=['GET', 'POST'])
|
||||
def submit():
|
||||
if request.method == 'POST':
|
||||
name = request.form.get('name')
|
||||
email = request.form.get('email')
|
||||
message = request.form.get('message')
|
||||
|
||||
# Validate the data
|
||||
if not name or not email or not message:
|
||||
return render_template('form.html', error='All fields are required.')
|
||||
|
||||
# Process the data (save to DB, send email, etc.)
|
||||
return render_template('success.html', name=name)
|
||||
|
||||
return render_template('form.html')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Static Files
|
||||
|
||||
Flask serves static files from the `static/` folder by default.
|
||||
|
||||
### Serving Static Files
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||
<img src="{{ url_for('static', filename='images/logo.png') }}" alt="Logo">
|
||||
```
|
||||
|
||||
### Static File Organization
|
||||
|
||||
```
|
||||
static/
|
||||
css/
|
||||
style.css
|
||||
js/
|
||||
main.js
|
||||
images/
|
||||
logo.png
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Sessions and Cookies
|
||||
|
||||
### Using Sessions
|
||||
|
||||
```python
|
||||
from flask import session
|
||||
|
||||
app.secret_key = 'your-secret-key'
|
||||
|
||||
@app.route('/login', methods=['POST'])
|
||||
def login():
|
||||
session['username'] = request.form['username']
|
||||
return redirect(url_for('index'))
|
||||
|
||||
@app.route('/logout')
|
||||
def logout():
|
||||
session.pop('username', None)
|
||||
return redirect(url_for('index'))
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
if 'username' in session:
|
||||
return f'Logged in as {session["username"]}'
|
||||
return 'You are not logged in'
|
||||
```
|
||||
|
||||
### Setting Cookies
|
||||
|
||||
```python
|
||||
from flask import make_response
|
||||
|
||||
@app.route('/set-cookie')
|
||||
def set_cookie():
|
||||
response = make_response('Cookie set!')
|
||||
response.set_cookie('username', 'flask_user', max_age=3600)
|
||||
return response
|
||||
|
||||
@app.route('/get-cookie')
|
||||
def get_cookie():
|
||||
username = request.cookies.get('username')
|
||||
return f'Username: {username}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Custom Error Pages
|
||||
|
||||
```python
|
||||
@app.errorhandler(404)
|
||||
def page_not_found(error):
|
||||
return render_template('404.html'), 404
|
||||
|
||||
@app.errorhandler(500)
|
||||
def internal_server_error(error):
|
||||
return render_template('500.html'), 500
|
||||
```
|
||||
|
||||
### Aborting Requests
|
||||
|
||||
```python
|
||||
from flask import abort
|
||||
|
||||
@app.route('/user/<int:user_id>')
|
||||
def get_user(user_id):
|
||||
user = find_user(user_id)
|
||||
if user is None:
|
||||
abort(404)
|
||||
return render_template('user.html', user=user)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Redirects
|
||||
|
||||
```python
|
||||
from flask import redirect, url_for
|
||||
|
||||
@app.route('/old-page')
|
||||
def old_page():
|
||||
return redirect(url_for('new_page'))
|
||||
|
||||
@app.route('/new-page')
|
||||
def new_page():
|
||||
return 'This is the new page.'
|
||||
|
||||
# Redirect with status code
|
||||
@app.route('/moved')
|
||||
def moved():
|
||||
return redirect(url_for('new_page'), code=301)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Flask Extensions
|
||||
|
||||
Common Flask extensions for building web applications:
|
||||
|
||||
| Extension | Purpose |
|
||||
|-----------|---------|
|
||||
| **Flask-SQLAlchemy** | Database ORM integration |
|
||||
| **Flask-WTF** | Form handling with WTForms and CSRF protection |
|
||||
| **Flask-Login** | User session management and authentication |
|
||||
| **Flask-Mail** | Email sending support |
|
||||
| **Flask-Migrate** | Database migration management via Alembic |
|
||||
| **Flask-RESTful** | Building REST APIs |
|
||||
| **Flask-CORS** | Cross-Origin Resource Sharing support |
|
||||
| **Flask-Caching** | Response caching |
|
||||
| **Flask-Limiter** | Rate limiting for API endpoints |
|
||||
|
||||
---
|
||||
|
||||
## Key Takeaways
|
||||
|
||||
1. **Flask is a micro-framework** -- it provides the essentials (routing, templates, request handling) and lets you choose extensions for everything else.
|
||||
2. **Routing maps URLs to functions** using the `@app.route()` decorator with support for dynamic URL parameters and multiple HTTP methods.
|
||||
3. **Jinja2 templates** support inheritance, loops, conditionals, and variable output for building dynamic HTML pages.
|
||||
4. **The `request` object** gives access to form data, query parameters, headers, cookies, and uploaded files.
|
||||
5. **Use `url_for()`** to build URLs dynamically instead of hard-coding paths.
|
||||
6. **Debug mode** is essential for development but must be disabled in production.
|
||||
7. **Virtual environments** isolate project dependencies and should always be used.
|
||||
8. **Static files** are served from the `static/` directory and referenced using `url_for('static', filename='...')`.
|
||||
9. **Sessions** provide server-side user state management, requiring a `SECRET_KEY` configuration.
|
||||
10. **Flask extensions** provide modular functionality for databases, forms, authentication, email, and more.
|
||||
453
skills/create-web-form/references/python-contact-form.md
Normal file
453
skills/create-web-form/references/python-contact-form.md
Normal file
@@ -0,0 +1,453 @@
|
||||
# Python Contact Form Reference
|
||||
|
||||
> Source: <https://mailtrap.io/blog/python-contact-form/>
|
||||
|
||||
This reference covers how to build a contact form in Python, including creating HTML forms, handling form submissions with Flask, sending emails with `smtplib`, and validating user input.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
A Python contact form typically involves:
|
||||
|
||||
- An **HTML front end** with a form for user input (name, email, message)
|
||||
- A **Python back end** (usually Flask or Django) to receive and process form data
|
||||
- An **email-sending mechanism** (using `smtplib` or a transactional email API) to deliver form submissions
|
||||
- **Input validation** on both the client side (HTML5 attributes) and server side (Python logic)
|
||||
|
||||
---
|
||||
|
||||
## Setting Up a Flask Project
|
||||
|
||||
### Install Flask
|
||||
|
||||
```bash
|
||||
pip install Flask
|
||||
```
|
||||
|
||||
### Basic Project Structure
|
||||
|
||||
```
|
||||
contact-form/
|
||||
app.py
|
||||
templates/
|
||||
contact.html
|
||||
success.html
|
||||
static/
|
||||
style.css
|
||||
```
|
||||
|
||||
### Minimal Flask Application
|
||||
|
||||
```python
|
||||
from flask import Flask, render_template, request, redirect, url_for
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route('/')
|
||||
def home():
|
||||
return render_template('contact.html')
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Creating the HTML Contact Form
|
||||
|
||||
### Basic Contact Form Template
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Contact Us</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Contact Us</h1>
|
||||
<form method="POST" action="/contact">
|
||||
<div>
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" id="name" name="name" required />
|
||||
</div>
|
||||
<div>
|
||||
<label for="email">Email:</label>
|
||||
<input type="email" id="email" name="email" required />
|
||||
</div>
|
||||
<div>
|
||||
<label for="subject">Subject:</label>
|
||||
<input type="text" id="subject" name="subject" required />
|
||||
</div>
|
||||
<div>
|
||||
<label for="message">Message:</label>
|
||||
<textarea id="message" name="message" rows="5" required></textarea>
|
||||
</div>
|
||||
<button type="submit">Send Message</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### Key HTML Form Attributes
|
||||
|
||||
| Attribute | Description |
|
||||
|------------|-------------|
|
||||
| `method` | HTTP method -- use `POST` for contact forms to keep data out of the URL |
|
||||
| `action` | The server endpoint that processes the form data |
|
||||
| `required` | HTML5 attribute that enforces client-side validation |
|
||||
| `name` | Identifies each field in the submitted form data |
|
||||
|
||||
---
|
||||
|
||||
## Handling Form Submissions in Flask
|
||||
|
||||
### Processing POST Requests
|
||||
|
||||
```python
|
||||
from flask import Flask, render_template, request, redirect, url_for, flash
|
||||
|
||||
app = Flask(__name__)
|
||||
app.secret_key = 'your-secret-key'
|
||||
|
||||
@app.route('/contact', methods=['GET', 'POST'])
|
||||
def contact():
|
||||
if request.method == 'POST':
|
||||
name = request.form.get('name')
|
||||
email = request.form.get('email')
|
||||
subject = request.form.get('subject')
|
||||
message = request.form.get('message')
|
||||
|
||||
# Validate inputs
|
||||
if not name or not email or not message:
|
||||
flash('Please fill in all required fields.', 'error')
|
||||
return redirect(url_for('contact'))
|
||||
|
||||
# Send the email
|
||||
send_email(name, email, subject, message)
|
||||
|
||||
flash('Your message has been sent successfully!', 'success')
|
||||
return redirect(url_for('contact'))
|
||||
|
||||
return render_template('contact.html')
|
||||
```
|
||||
|
||||
### Accessing Form Data
|
||||
|
||||
Flask provides `request.form` to access submitted form data:
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `request.form['key']` | Raises `KeyError` if the key is missing |
|
||||
| `request.form.get('key')` | Returns `None` if the key is missing (safer) |
|
||||
| `request.form.get('key', 'default')` | Returns a default value if the key is missing |
|
||||
|
||||
---
|
||||
|
||||
## Sending Emails with `smtplib`
|
||||
|
||||
### Basic Email Sending Function
|
||||
|
||||
```python
|
||||
import smtplib
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
|
||||
def send_email(name, email, subject, message):
|
||||
sender_email = "your-email@example.com"
|
||||
receiver_email = "recipient@example.com"
|
||||
password = "your-email-password"
|
||||
|
||||
# Create the email message
|
||||
msg = MIMEMultipart()
|
||||
msg['From'] = sender_email
|
||||
msg['To'] = receiver_email
|
||||
msg['Subject'] = f"Contact Form: {subject}"
|
||||
|
||||
# Email body
|
||||
body = f"""
|
||||
New contact form submission:
|
||||
|
||||
Name: {name}
|
||||
Email: {email}
|
||||
Subject: {subject}
|
||||
Message: {message}
|
||||
"""
|
||||
msg.attach(MIMEText(body, 'plain'))
|
||||
|
||||
# Send the email
|
||||
try:
|
||||
with smtplib.SMTP('smtp.gmail.com', 587) as server:
|
||||
server.starttls()
|
||||
server.login(sender_email, password)
|
||||
server.send_message(msg)
|
||||
except Exception as e:
|
||||
print(f"Error sending email: {e}")
|
||||
raise
|
||||
```
|
||||
|
||||
### Common SMTP Server Settings
|
||||
|
||||
| Provider | SMTP Server | Port (TLS) | Port (SSL) |
|
||||
|----------|-------------|------------|------------|
|
||||
| Gmail | `smtp.gmail.com` | 587 | 465 |
|
||||
| Outlook | `smtp-mail.outlook.com` | 587 | -- |
|
||||
| Yahoo | `smtp.mail.yahoo.com` | 587 | 465 |
|
||||
| Mailtrap (testing) | `sandbox.smtp.mailtrap.io` | 587 | 465 |
|
||||
|
||||
### Using Environment Variables for Credentials
|
||||
|
||||
Never hard-code email credentials. Use environment variables instead:
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
SMTP_SERVER = os.environ.get('SMTP_SERVER', 'smtp.gmail.com')
|
||||
SMTP_PORT = int(os.environ.get('SMTP_PORT', 587))
|
||||
SMTP_USERNAME = os.environ.get('SMTP_USERNAME')
|
||||
SMTP_PASSWORD = os.environ.get('SMTP_PASSWORD')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Server-Side Validation
|
||||
|
||||
### Validating Form Input
|
||||
|
||||
```python
|
||||
import re
|
||||
|
||||
def validate_contact_form(name, email, message):
|
||||
errors = []
|
||||
|
||||
if not name or len(name.strip()) < 2:
|
||||
errors.append('Name must be at least 2 characters long.')
|
||||
|
||||
if not email or not re.match(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$', email):
|
||||
errors.append('Please provide a valid email address.')
|
||||
|
||||
if not message or len(message.strip()) < 10:
|
||||
errors.append('Message must be at least 10 characters long.')
|
||||
|
||||
return errors
|
||||
```
|
||||
|
||||
### Integrating Validation into the Route
|
||||
|
||||
```python
|
||||
@app.route('/contact', methods=['GET', 'POST'])
|
||||
def contact():
|
||||
if request.method == 'POST':
|
||||
name = request.form.get('name', '').strip()
|
||||
email = request.form.get('email', '').strip()
|
||||
subject = request.form.get('subject', '').strip()
|
||||
message = request.form.get('message', '').strip()
|
||||
|
||||
errors = validate_contact_form(name, email, message)
|
||||
|
||||
if errors:
|
||||
for error in errors:
|
||||
flash(error, 'error')
|
||||
return render_template('contact.html',
|
||||
name=name, email=email,
|
||||
subject=subject, message=message)
|
||||
|
||||
send_email(name, email, subject, message)
|
||||
flash('Message sent successfully!', 'success')
|
||||
return redirect(url_for('contact'))
|
||||
|
||||
return render_template('contact.html')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Using Mailtrap for Email Testing
|
||||
|
||||
Mailtrap provides a safe sandbox SMTP server for testing email sending without delivering to real inboxes.
|
||||
|
||||
### Mailtrap Configuration
|
||||
|
||||
```python
|
||||
import smtplib
|
||||
from email.mime.text import MIMEText
|
||||
|
||||
def send_test_email(name, email, subject, message):
|
||||
sender = "from@example.com"
|
||||
receiver = "to@example.com"
|
||||
|
||||
body = f"Name: {name}\nEmail: {email}\nSubject: {subject}\nMessage: {message}"
|
||||
|
||||
msg = MIMEText(body)
|
||||
msg['Subject'] = f"Contact Form: {subject}"
|
||||
msg['From'] = sender
|
||||
msg['To'] = receiver
|
||||
|
||||
with smtplib.SMTP("sandbox.smtp.mailtrap.io", 2525) as server:
|
||||
server.login("your_mailtrap_username", "your_mailtrap_password")
|
||||
server.sendmail(sender, receiver, msg.as_string())
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Using Flask-Mail Extension
|
||||
|
||||
Flask-Mail simplifies email configuration and sending within Flask applications.
|
||||
|
||||
### Installation and Setup
|
||||
|
||||
```bash
|
||||
pip install Flask-Mail
|
||||
```
|
||||
|
||||
```python
|
||||
from flask import Flask
|
||||
from flask_mail import Mail, Message
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
app.config['MAIL_SERVER'] = 'smtp.gmail.com'
|
||||
app.config['MAIL_PORT'] = 587
|
||||
app.config['MAIL_USE_TLS'] = True
|
||||
app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME')
|
||||
app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD')
|
||||
app.config['MAIL_DEFAULT_SENDER'] = os.environ.get('MAIL_DEFAULT_SENDER')
|
||||
|
||||
mail = Mail(app)
|
||||
```
|
||||
|
||||
### Sending Email with Flask-Mail
|
||||
|
||||
```python
|
||||
@app.route('/contact', methods=['POST'])
|
||||
def contact():
|
||||
name = request.form.get('name')
|
||||
email = request.form.get('email')
|
||||
subject = request.form.get('subject')
|
||||
message_body = request.form.get('message')
|
||||
|
||||
msg = Message(
|
||||
subject=f"Contact Form: {subject}",
|
||||
recipients=['admin@example.com'],
|
||||
reply_to=email
|
||||
)
|
||||
msg.body = f"From: {name} ({email})\n\n{message_body}"
|
||||
|
||||
try:
|
||||
mail.send(msg)
|
||||
flash('Message sent successfully!', 'success')
|
||||
except Exception as e:
|
||||
flash('An error occurred. Please try again later.', 'error')
|
||||
|
||||
return redirect(url_for('contact'))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CSRF Protection
|
||||
|
||||
Cross-Site Request Forgery (CSRF) protection prevents malicious sites from submitting forms on behalf of a user.
|
||||
|
||||
### Using Flask-WTF for CSRF
|
||||
|
||||
```bash
|
||||
pip install Flask-WTF
|
||||
```
|
||||
|
||||
```python
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, TextAreaField, SubmitField
|
||||
from wtforms.validators import DataRequired, Email
|
||||
|
||||
class ContactForm(FlaskForm):
|
||||
name = StringField('Name', validators=[DataRequired()])
|
||||
email = StringField('Email', validators=[DataRequired(), Email()])
|
||||
subject = StringField('Subject', validators=[DataRequired()])
|
||||
message = TextAreaField('Message', validators=[DataRequired()])
|
||||
submit = SubmitField('Send Message')
|
||||
```
|
||||
|
||||
In the template, include the CSRF token:
|
||||
|
||||
```html
|
||||
<form method="POST" action="/contact">
|
||||
{{ form.hidden_tag() }}
|
||||
<!-- form fields here -->
|
||||
</form>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Complete Example Application
|
||||
|
||||
```python
|
||||
import os
|
||||
import smtplib
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from flask import Flask, render_template, request, redirect, url_for, flash
|
||||
|
||||
app = Flask(__name__)
|
||||
app.secret_key = os.environ.get('SECRET_KEY', 'dev-secret-key')
|
||||
|
||||
def send_email(name, email, subject, message):
|
||||
sender = os.environ.get('MAIL_USERNAME')
|
||||
receiver = os.environ.get('MAIL_RECIPIENT')
|
||||
password = os.environ.get('MAIL_PASSWORD')
|
||||
|
||||
msg = MIMEMultipart()
|
||||
msg['From'] = sender
|
||||
msg['To'] = receiver
|
||||
msg['Subject'] = f"Contact Form: {subject}"
|
||||
|
||||
body = f"Name: {name}\nEmail: {email}\nSubject: {subject}\n\n{message}"
|
||||
msg.attach(MIMEText(body, 'plain'))
|
||||
|
||||
with smtplib.SMTP(os.environ.get('SMTP_SERVER', 'smtp.gmail.com'), 587) as server:
|
||||
server.starttls()
|
||||
server.login(sender, password)
|
||||
server.send_message(msg)
|
||||
|
||||
@app.route('/')
|
||||
def home():
|
||||
return redirect(url_for('contact'))
|
||||
|
||||
@app.route('/contact', methods=['GET', 'POST'])
|
||||
def contact():
|
||||
if request.method == 'POST':
|
||||
name = request.form.get('name', '').strip()
|
||||
email = request.form.get('email', '').strip()
|
||||
subject = request.form.get('subject', '').strip()
|
||||
message = request.form.get('message', '').strip()
|
||||
|
||||
if not all([name, email, message]):
|
||||
flash('Please fill in all required fields.', 'error')
|
||||
return render_template('contact.html')
|
||||
|
||||
try:
|
||||
send_email(name, email, subject, message)
|
||||
flash('Your message has been sent!', 'success')
|
||||
except Exception:
|
||||
flash('Failed to send message. Please try again.', 'error')
|
||||
|
||||
return redirect(url_for('contact'))
|
||||
|
||||
return render_template('contact.html')
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Takeaways
|
||||
|
||||
1. **Use Flask** as a lightweight Python web framework for handling contact form submissions via `request.form`.
|
||||
2. **Use `smtplib`** or **Flask-Mail** for sending emails from the contact form.
|
||||
3. **Validate input** on both the client side (HTML5 `required`, `type="email"`) and server side (Python regex, length checks).
|
||||
4. **Never hard-code credentials** -- use environment variables or a `.env` file.
|
||||
5. **Use Mailtrap** or a similar service for testing email delivery without sending to real inboxes.
|
||||
6. **Add CSRF protection** using Flask-WTF to guard against cross-site request forgery attacks.
|
||||
7. **Flash messages** provide user feedback for successful submissions and validation errors.
|
||||
8. **Use `MIMEMultipart`** for constructing well-formatted email messages with headers and body content.
|
||||
449
skills/create-web-form/references/python-flask-app.md
Normal file
449
skills/create-web-form/references/python-flask-app.md
Normal file
@@ -0,0 +1,449 @@
|
||||
# Python Flask App Reference
|
||||
|
||||
> Source: <https://realpython.com/python-web-applications/>
|
||||
|
||||
This reference covers building Python web applications, including how the web works, choosing a framework, building and deploying a Flask application, and understanding key web development concepts.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Python offers several approaches to web development:
|
||||
|
||||
- **Web frameworks** (Flask, Django, FastAPI) that handle routing, templates, and data
|
||||
- **Hosting platforms** (Google App Engine, PythonAnywhere, Heroku, etc.) for deployment
|
||||
- **WSGI** (Web Server Gateway Interface) as the standard interface between web servers and Python applications
|
||||
|
||||
---
|
||||
|
||||
## How the Web Works
|
||||
|
||||
### The HTTP Request-Response Cycle
|
||||
|
||||
1. A client (browser) sends an **HTTP request** to a server
|
||||
2. The server processes the request and returns an **HTTP response**
|
||||
3. The browser renders the response content
|
||||
|
||||
### HTTP Methods
|
||||
|
||||
| Method | Purpose |
|
||||
|--------|---------|
|
||||
| `GET` | Retrieve data from the server |
|
||||
| `POST` | Submit data to the server |
|
||||
| `PUT` | Update existing data on the server |
|
||||
| `DELETE` | Remove data from the server |
|
||||
|
||||
### URL Structure
|
||||
|
||||
```
|
||||
https://example.com:443/path/to/resource?key=value#section
|
||||
| | | | | |
|
||||
scheme host port path query fragment
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Choosing a Python Web Framework
|
||||
|
||||
### Flask
|
||||
|
||||
- **Micro-framework** -- minimal core with extensions for added functionality
|
||||
- Best for small to medium applications, APIs, and learning
|
||||
- No database abstraction layer, form validation, or other components built in
|
||||
- Extensions available for everything (SQLAlchemy, WTForms, Login, etc.)
|
||||
|
||||
### Django
|
||||
|
||||
- **Full-stack framework** -- batteries included
|
||||
- Best for large applications with built-in ORM, admin panel, authentication
|
||||
- Opinionated project structure
|
||||
|
||||
### FastAPI
|
||||
|
||||
- **Modern, fast, async framework** -- built on Starlette and Pydantic
|
||||
- Best for building APIs with automatic documentation
|
||||
- Built-in data validation and serialization
|
||||
|
||||
---
|
||||
|
||||
## Building a Flask Application
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
python -m pip install flask
|
||||
```
|
||||
|
||||
### Minimal Application
|
||||
|
||||
```python
|
||||
from flask import Flask
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route('/')
|
||||
def home():
|
||||
return 'Hello, World!'
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=5000, debug=True)
|
||||
```
|
||||
|
||||
### Running the Application
|
||||
|
||||
```bash
|
||||
# Method 1: Direct execution
|
||||
python app.py
|
||||
|
||||
# Method 2: Using Flask CLI
|
||||
export FLASK_APP=app.py
|
||||
export FLASK_ENV=development
|
||||
flask run
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Routing
|
||||
|
||||
### Basic Routes
|
||||
|
||||
```python
|
||||
@app.route('/')
|
||||
def home():
|
||||
return 'Home Page'
|
||||
|
||||
@app.route('/about')
|
||||
def about():
|
||||
return 'About Page'
|
||||
|
||||
@app.route('/contact')
|
||||
def contact():
|
||||
return 'Contact Page'
|
||||
```
|
||||
|
||||
### Dynamic Routes with URL Parameters
|
||||
|
||||
```python
|
||||
@app.route('/user/<username>')
|
||||
def show_user(username):
|
||||
return f'User: {username}'
|
||||
|
||||
@app.route('/post/<int:post_id>')
|
||||
def show_post(post_id):
|
||||
return f'Post ID: {post_id}'
|
||||
```
|
||||
|
||||
### URL Converters
|
||||
|
||||
| Converter | Description |
|
||||
|-----------|-------------|
|
||||
| `string` | Accepts any text without a slash (default) |
|
||||
| `int` | Accepts positive integers |
|
||||
| `float` | Accepts positive floating-point values |
|
||||
| `path` | Like `string` but also accepts slashes |
|
||||
| `uuid` | Accepts UUID strings |
|
||||
|
||||
### Specifying HTTP Methods
|
||||
|
||||
```python
|
||||
@app.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
if request.method == 'POST':
|
||||
return do_login()
|
||||
return show_login_form()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Templates with Jinja2
|
||||
|
||||
### Basic Template Rendering
|
||||
|
||||
```python
|
||||
from flask import render_template
|
||||
|
||||
@app.route('/hello/<name>')
|
||||
def hello(name):
|
||||
return render_template('hello.html', name=name)
|
||||
```
|
||||
|
||||
### Template Inheritance
|
||||
|
||||
**Base template (`templates/base.html`):**
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}My App{% endblock %}</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<a href="{{ url_for('home') }}">Home</a>
|
||||
<a href="{{ url_for('about') }}">About</a>
|
||||
</nav>
|
||||
|
||||
<main>
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>My Web App</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
**Child template (`templates/home.html`):**
|
||||
|
||||
```html
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Home{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Welcome to My App</h1>
|
||||
<p>This is the home page.</p>
|
||||
{% endblock %}
|
||||
```
|
||||
|
||||
### Jinja2 Template Syntax
|
||||
|
||||
| Syntax | Purpose |
|
||||
|--------|---------|
|
||||
| `{{ variable }}` | Output the value of a variable |
|
||||
| `{% statement %}` | Execute a control flow statement |
|
||||
| `{# comment #}` | Template comment (not rendered) |
|
||||
| `{{ url_for('func') }}` | Generate a URL for a view function |
|
||||
| `{{ url_for('static', filename='style.css') }}` | Generate a URL for a static file |
|
||||
|
||||
### Control Flow in Templates
|
||||
|
||||
```html
|
||||
{% if user %}
|
||||
<h1>Hello, {{ user.name }}!</h1>
|
||||
{% else %}
|
||||
<h1>Hello, stranger!</h1>
|
||||
{% endif %}
|
||||
|
||||
<ul>
|
||||
{% for item in items %}
|
||||
<li>{{ item }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Recommended Flask Project Layout
|
||||
|
||||
```
|
||||
my_flask_app/
|
||||
app.py # Application entry point
|
||||
config.py # Configuration settings
|
||||
requirements.txt # Python dependencies
|
||||
static/ # Static files (CSS, JS, images)
|
||||
style.css
|
||||
script.js
|
||||
templates/ # Jinja2 HTML templates
|
||||
base.html
|
||||
home.html
|
||||
about.html
|
||||
models.py # Database models (if using a database)
|
||||
forms.py # WTForms form classes
|
||||
```
|
||||
|
||||
### Larger Application Structure (Blueprints)
|
||||
|
||||
```
|
||||
my_flask_app/
|
||||
app/
|
||||
__init__.py # Application factory
|
||||
models.py
|
||||
auth/
|
||||
__init__.py
|
||||
routes.py
|
||||
forms.py
|
||||
templates/
|
||||
login.html
|
||||
register.html
|
||||
main/
|
||||
__init__.py
|
||||
routes.py
|
||||
templates/
|
||||
home.html
|
||||
about.html
|
||||
config.py
|
||||
requirements.txt
|
||||
run.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Working with Static Files
|
||||
|
||||
Flask automatically serves files from the `static/` directory.
|
||||
|
||||
### Referencing Static Files in Templates
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
<script src="{{ url_for('static', filename='script.js') }}"></script>
|
||||
<img src="{{ url_for('static', filename='images/logo.png') }}" alt="Logo">
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Database Integration
|
||||
|
||||
### Using Flask-SQLAlchemy
|
||||
|
||||
```bash
|
||||
pip install Flask-SQLAlchemy
|
||||
```
|
||||
|
||||
```python
|
||||
from flask import Flask
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
|
||||
db = SQLAlchemy(app)
|
||||
|
||||
class User(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
username = db.Column(db.String(80), unique=True, nullable=False)
|
||||
email = db.Column(db.String(120), unique=True, nullable=False)
|
||||
|
||||
def __repr__(self):
|
||||
return f'<User {self.username}>'
|
||||
```
|
||||
|
||||
### Creating the Database
|
||||
|
||||
```python
|
||||
with app.app_context():
|
||||
db.create_all()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deployment
|
||||
|
||||
### Deploying to PythonAnywhere
|
||||
|
||||
1. Create a free account at pythonanywhere.com
|
||||
2. Upload your code via git or the file browser
|
||||
3. Set up a virtual environment and install dependencies
|
||||
4. Configure a WSGI file pointing to your Flask app
|
||||
5. Reload the web application
|
||||
|
||||
### Deploying to Heroku
|
||||
|
||||
1. Create a `Procfile`:
|
||||
|
||||
```
|
||||
web: gunicorn app:app
|
||||
```
|
||||
|
||||
1. Create a `requirements.txt`:
|
||||
|
||||
```bash
|
||||
pip freeze > requirements.txt
|
||||
```
|
||||
|
||||
1. Deploy:
|
||||
|
||||
```bash
|
||||
heroku create
|
||||
git push heroku main
|
||||
```
|
||||
|
||||
### Deploying to Google App Engine
|
||||
|
||||
Create an `app.yaml` configuration:
|
||||
|
||||
```yaml
|
||||
runtime: python39
|
||||
entrypoint: gunicorn -b :$PORT app:app
|
||||
|
||||
handlers:
|
||||
- url: /static
|
||||
static_dir: static
|
||||
- url: /.*
|
||||
script: auto
|
||||
```
|
||||
|
||||
### WSGI Servers
|
||||
|
||||
For production, use a WSGI server instead of Flask's built-in development server:
|
||||
|
||||
| Server | Description |
|
||||
|--------|-------------|
|
||||
| **Gunicorn** | Production-grade WSGI server for Unix |
|
||||
| **Waitress** | Production-grade WSGI server for Windows and Unix |
|
||||
| **uWSGI** | Full-featured WSGI server with many deployment options |
|
||||
|
||||
```bash
|
||||
# Using Gunicorn
|
||||
pip install gunicorn
|
||||
gunicorn app:app
|
||||
|
||||
# Using Waitress
|
||||
pip install waitress
|
||||
waitress-serve --port=5000 app:app
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Environment Configuration
|
||||
|
||||
### Using Environment Variables
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
class Config:
|
||||
SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-fallback-key')
|
||||
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL', 'sqlite:///site.db')
|
||||
DEBUG = os.environ.get('FLASK_DEBUG', False)
|
||||
```
|
||||
|
||||
### Using python-dotenv
|
||||
|
||||
```bash
|
||||
pip install python-dotenv
|
||||
```
|
||||
|
||||
Create a `.env` file:
|
||||
|
||||
```
|
||||
SECRET_KEY=your-secret-key-here
|
||||
DATABASE_URL=sqlite:///site.db
|
||||
FLASK_DEBUG=1
|
||||
```
|
||||
|
||||
Load in your application:
|
||||
|
||||
```python
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Takeaways
|
||||
|
||||
1. **Flask is a micro-framework** -- it provides routing, templates, and request handling while leaving other choices (database, forms, authentication) to extensions.
|
||||
2. **Use Jinja2 template inheritance** to keep HTML DRY with base templates and child blocks.
|
||||
3. **Organize your project** with a clear structure: separate `templates/`, `static/`, and Python modules.
|
||||
4. **Use Blueprints** for larger applications to group related routes and templates.
|
||||
5. **Never use the Flask development server in production** -- use Gunicorn, Waitress, or uWSGI.
|
||||
6. **Store configuration in environment variables** using `python-dotenv` or platform-specific config.
|
||||
7. **Use `url_for()`** to generate URLs dynamically rather than hard-coding paths.
|
||||
8. **Flask-SQLAlchemy** provides a convenient ORM layer for database operations.
|
||||
9. **Multiple hosting platforms** support Flask apps: PythonAnywhere, Heroku, Google App Engine, and others.
|
||||
432
skills/create-web-form/references/python-flask.md
Normal file
432
skills/create-web-form/references/python-flask.md
Normal file
@@ -0,0 +1,432 @@
|
||||
# Python Flask Forms Reference
|
||||
|
||||
> Source: <https://testdriven.io/courses/learn-flask/forms/>
|
||||
|
||||
This reference covers how to work with forms in Flask, including handling GET and POST requests, using WTForms for form creation and validation, implementing CSRF protection, and managing file uploads.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Flask provides tools for handling web forms through:
|
||||
|
||||
- The `request` object for accessing submitted form data
|
||||
- **Flask-WTF** and **WTForms** for declarative form creation, validation, and CSRF protection
|
||||
- Jinja2 templates for rendering form HTML
|
||||
- Flash messages for user feedback
|
||||
|
||||
---
|
||||
|
||||
## Basic Form Handling in Flask
|
||||
|
||||
### Handling GET and POST Requests
|
||||
|
||||
```python
|
||||
from flask import Flask, render_template, request, redirect, url_for, flash
|
||||
|
||||
app = Flask(__name__)
|
||||
app.secret_key = 'your-secret-key'
|
||||
|
||||
@app.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
if request.method == 'POST':
|
||||
username = request.form.get('username')
|
||||
password = request.form.get('password')
|
||||
|
||||
if username == 'admin' and password == 'secret':
|
||||
flash('Login successful!', 'success')
|
||||
return redirect(url_for('dashboard'))
|
||||
else:
|
||||
flash('Invalid credentials.', 'error')
|
||||
|
||||
return render_template('login.html')
|
||||
```
|
||||
|
||||
### The `request.form` Object
|
||||
|
||||
The `request.form` is an `ImmutableMultiDict` that contains parsed form data from POST and PUT requests.
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `request.form['key']` | Access a value; raises `400 Bad Request` if missing |
|
||||
| `request.form.get('key')` | Access a value; returns `None` if missing |
|
||||
| `request.form.get('key', 'default')` | Access a value with a fallback default |
|
||||
| `request.form.getlist('key')` | Returns a list of all values for a key (for multi-select fields) |
|
||||
|
||||
### The `request.method` Attribute
|
||||
|
||||
Used to distinguish between GET (displaying the form) and POST (processing the submission):
|
||||
|
||||
```python
|
||||
@app.route('/register', methods=['GET', 'POST'])
|
||||
def register():
|
||||
if request.method == 'POST':
|
||||
# Process the form submission
|
||||
pass
|
||||
# GET: Display the form
|
||||
return render_template('register.html')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Flask-WTF and WTForms
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
pip install Flask-WTF
|
||||
```
|
||||
|
||||
Flask-WTF is a Flask extension that integrates WTForms. It provides:
|
||||
|
||||
- CSRF protection out of the box
|
||||
- Integration with Flask's `request` object
|
||||
- Jinja2 template helpers
|
||||
- File upload support
|
||||
|
||||
### Configuration
|
||||
|
||||
```python
|
||||
from flask import Flask
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config['SECRET_KEY'] = 'your-secret-key' # Required for CSRF
|
||||
app.config['WTF_CSRF_ENABLED'] = True # Enabled by default
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Defining Forms with WTForms
|
||||
|
||||
### Basic Form Class
|
||||
|
||||
```python
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, PasswordField, TextAreaField, SubmitField
|
||||
from wtforms.validators import DataRequired, Email, Length, EqualTo
|
||||
|
||||
class RegistrationForm(FlaskForm):
|
||||
username = StringField('Username', validators=[
|
||||
DataRequired(),
|
||||
Length(min=3, max=25)
|
||||
])
|
||||
email = StringField('Email', validators=[
|
||||
DataRequired(),
|
||||
Email()
|
||||
])
|
||||
password = PasswordField('Password', validators=[
|
||||
DataRequired(),
|
||||
Length(min=6)
|
||||
])
|
||||
confirm_password = PasswordField('Confirm Password', validators=[
|
||||
DataRequired(),
|
||||
EqualTo('password', message='Passwords must match.')
|
||||
])
|
||||
submit = SubmitField('Register')
|
||||
```
|
||||
|
||||
### Common Field Types
|
||||
|
||||
| Field Type | Description |
|
||||
|-----------|-------------|
|
||||
| `StringField` | Single-line text input |
|
||||
| `PasswordField` | Password input (masked characters) |
|
||||
| `TextAreaField` | Multi-line text input |
|
||||
| `IntegerField` | Integer input with built-in type coercion |
|
||||
| `FloatField` | Float input with built-in type coercion |
|
||||
| `BooleanField` | Checkbox (True/False) |
|
||||
| `SelectField` | Dropdown select menu |
|
||||
| `SelectMultipleField` | Multiple-select dropdown |
|
||||
| `RadioField` | Radio button group |
|
||||
| `FileField` | File upload input |
|
||||
| `HiddenField` | Hidden input field |
|
||||
| `SubmitField` | Submit button |
|
||||
| `DateField` | Date picker input |
|
||||
|
||||
### Common Validators
|
||||
|
||||
| Validator | Description |
|
||||
|-----------|-------------|
|
||||
| `DataRequired()` | Field must not be empty |
|
||||
| `Email()` | Must be a valid email format |
|
||||
| `Length(min, max)` | String length must fall within range |
|
||||
| `EqualTo('field')` | Must match another field's value |
|
||||
| `NumberRange(min, max)` | Numeric value must fall within range |
|
||||
| `Regexp(regex)` | Must match the provided regular expression |
|
||||
| `URL()` | Must be a valid URL |
|
||||
| `Optional()` | Field is allowed to be empty |
|
||||
| `InputRequired()` | Raw input data must be present |
|
||||
| `AnyOf(values)` | Must be one of the provided values |
|
||||
| `NoneOf(values)` | Must not be any of the provided values |
|
||||
|
||||
---
|
||||
|
||||
## Using Forms in Routes
|
||||
|
||||
### Route with WTForms
|
||||
|
||||
```python
|
||||
@app.route('/register', methods=['GET', 'POST'])
|
||||
def register():
|
||||
form = RegistrationForm()
|
||||
|
||||
if form.validate_on_submit():
|
||||
# form.validate_on_submit() checks:
|
||||
# 1. Is the request method POST?
|
||||
# 2. Does the form pass all validation?
|
||||
# 3. Is the CSRF token valid?
|
||||
|
||||
username = form.username.data
|
||||
email = form.email.data
|
||||
password = form.password.data
|
||||
|
||||
# Process the data (e.g., save to database)
|
||||
flash(f'Account created for {username}!', 'success')
|
||||
return redirect(url_for('login'))
|
||||
|
||||
return render_template('register.html', form=form)
|
||||
```
|
||||
|
||||
### `validate_on_submit()` Method
|
||||
|
||||
This method combines two checks:
|
||||
|
||||
1. `request.method == 'POST'` -- ensures the form was actually submitted
|
||||
2. `form.validate()` -- runs all validators on the form fields and checks the CSRF token
|
||||
|
||||
Returns `True` only if both conditions are met.
|
||||
|
||||
---
|
||||
|
||||
## Rendering Forms in Templates
|
||||
|
||||
### Basic Template Rendering
|
||||
|
||||
```html
|
||||
<form method="POST" action="{{ url_for('register') }}">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
<div>
|
||||
{{ form.username.label }}
|
||||
{{ form.username(class="form-control", placeholder="Enter username") }}
|
||||
{% for error in form.username.errors %}
|
||||
<span class="error">{{ error }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{ form.email.label }}
|
||||
{{ form.email(class="form-control", placeholder="Enter email") }}
|
||||
{% for error in form.email.errors %}
|
||||
<span class="error">{{ error }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{ form.password.label }}
|
||||
{{ form.password(class="form-control") }}
|
||||
{% for error in form.password.errors %}
|
||||
<span class="error">{{ error }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{ form.confirm_password.label }}
|
||||
{{ form.confirm_password(class="form-control") }}
|
||||
{% for error in form.confirm_password.errors %}
|
||||
<span class="error">{{ error }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{{ form.submit(class="btn btn-primary") }}
|
||||
</form>
|
||||
```
|
||||
|
||||
### Key Template Elements
|
||||
|
||||
| Element | Purpose |
|
||||
|---------|---------|
|
||||
| `{{ form.hidden_tag() }}` | Renders the hidden CSRF token field |
|
||||
| `{{ form.field.label }}` | Renders the `<label>` element for the field |
|
||||
| `{{ form.field() }}` | Renders the `<input>` element for the field |
|
||||
| `{{ form.field(class="...") }}` | Renders the input with additional HTML attributes |
|
||||
| `{{ form.field.errors }}` | List of validation error messages for the field |
|
||||
| `{{ form.field.data }}` | The current value of the field |
|
||||
|
||||
---
|
||||
|
||||
## CSRF Protection
|
||||
|
||||
### How CSRF Protection Works
|
||||
|
||||
Flask-WTF automatically includes CSRF protection:
|
||||
|
||||
1. A unique token is generated per session and embedded as a hidden form field.
|
||||
2. When the form is submitted, Flask-WTF verifies the token matches the session token.
|
||||
3. If the token is missing or invalid, the request is rejected with a `400 Bad Request`.
|
||||
|
||||
### Including the CSRF Token
|
||||
|
||||
In your template, always include one of these:
|
||||
|
||||
```html
|
||||
<!-- Option 1: Hidden tag (includes CSRF + all hidden fields) -->
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
<!-- Option 2: CSRF token only -->
|
||||
{{ form.csrf_token }}
|
||||
```
|
||||
|
||||
### CSRF for AJAX Requests
|
||||
|
||||
For JavaScript-based form submissions:
|
||||
|
||||
```html
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
```
|
||||
|
||||
```javascript
|
||||
fetch('/api/submit', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').content
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Custom Validators
|
||||
|
||||
### Inline Custom Validator
|
||||
|
||||
Define a method on the form class with the naming pattern `validate_<fieldname>`:
|
||||
|
||||
```python
|
||||
from wtforms import ValidationError
|
||||
|
||||
class RegistrationForm(FlaskForm):
|
||||
username = StringField('Username', validators=[DataRequired()])
|
||||
email = StringField('Email', validators=[DataRequired(), Email()])
|
||||
|
||||
def validate_username(self, field):
|
||||
if field.data.lower() in ['admin', 'root', 'superuser']:
|
||||
raise ValidationError('That username is reserved.')
|
||||
|
||||
def validate_email(self, field):
|
||||
# Check if email already exists in database
|
||||
if User.query.filter_by(email=field.data).first():
|
||||
raise ValidationError('That email is already registered.')
|
||||
```
|
||||
|
||||
### Reusable Custom Validator
|
||||
|
||||
```python
|
||||
from wtforms import ValidationError
|
||||
|
||||
def validate_no_special_chars(form, field):
|
||||
if not field.data.isalnum():
|
||||
raise ValidationError('Field must contain only letters and numbers.')
|
||||
|
||||
class MyForm(FlaskForm):
|
||||
username = StringField('Username', validators=[
|
||||
DataRequired(),
|
||||
validate_no_special_chars
|
||||
])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File Uploads
|
||||
|
||||
### Form with File Upload
|
||||
|
||||
```python
|
||||
from flask_wtf.file import FileField, FileAllowed, FileRequired
|
||||
|
||||
class UploadForm(FlaskForm):
|
||||
photo = FileField('Profile Photo', validators=[
|
||||
FileRequired(),
|
||||
FileAllowed(['jpg', 'png', 'gif'], 'Images only!')
|
||||
])
|
||||
submit = SubmitField('Upload')
|
||||
```
|
||||
|
||||
### Handling File Uploads in Routes
|
||||
|
||||
```python
|
||||
import os
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
UPLOAD_FOLDER = 'static/uploads'
|
||||
|
||||
@app.route('/upload', methods=['GET', 'POST'])
|
||||
def upload():
|
||||
form = UploadForm()
|
||||
|
||||
if form.validate_on_submit():
|
||||
file = form.photo.data
|
||||
filename = secure_filename(file.filename)
|
||||
filepath = os.path.join(UPLOAD_FOLDER, filename)
|
||||
file.save(filepath)
|
||||
flash('File uploaded successfully!', 'success')
|
||||
return redirect(url_for('upload'))
|
||||
|
||||
return render_template('upload.html', form=form)
|
||||
```
|
||||
|
||||
### Multipart Form Encoding
|
||||
|
||||
File upload forms must use `enctype="multipart/form-data"`:
|
||||
|
||||
```html
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
{{ form.hidden_tag() }}
|
||||
{{ form.photo.label }}
|
||||
{{ form.photo() }}
|
||||
{{ form.submit() }}
|
||||
</form>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Flash Messages
|
||||
|
||||
### Setting Flash Messages
|
||||
|
||||
```python
|
||||
from flask import flash
|
||||
|
||||
flash('Operation successful!', 'success')
|
||||
flash('An error occurred.', 'error')
|
||||
flash('Please check your input.', 'warning')
|
||||
```
|
||||
|
||||
### Displaying Flash Messages in Templates
|
||||
|
||||
```html
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div class="alert alert-{{ category }}">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Takeaways
|
||||
|
||||
1. **Use Flask-WTF** for form handling -- it provides CSRF protection, validation, and clean form definitions.
|
||||
2. **`validate_on_submit()`** is the primary method for checking both submission and validation in one call.
|
||||
3. **Always include `{{ form.hidden_tag() }}`** in templates to enable CSRF protection.
|
||||
4. **Use WTForms validators** for clean, declarative server-side validation.
|
||||
5. **Custom validators** can be defined inline on the form class or as reusable functions.
|
||||
6. **Flash messages** provide user feedback for form actions.
|
||||
7. **File uploads** require `enctype="multipart/form-data"` and should use `secure_filename()` for safety.
|
||||
8. **Set a `SECRET_KEY`** in your Flask config -- it is required for CSRF tokens and session management.
|
||||
136
skills/create-web-form/references/security.md
Normal file
136
skills/create-web-form/references/security.md
Normal file
@@ -0,0 +1,136 @@
|
||||
# Web Security Reference
|
||||
|
||||
> Source: <https://developer.mozilla.org/en-US/docs/Web/Security>
|
||||
|
||||
## Overview
|
||||
|
||||
Web security focuses on protecting sensitive information (customer data, passwords, banking info, internal algorithms) from unauthorized access that could lead to competitive disadvantage, service disruption, or customer privacy violations.
|
||||
|
||||
## Security vs. Privacy
|
||||
|
||||
- **Security**: Protecting private data and systems against unauthorized access (internal and external data).
|
||||
- **Privacy**: Giving users control over data collection, storage, and usage with transparency and consent.
|
||||
|
||||
## Security Features Provided by Browsers
|
||||
|
||||
### Same-Origin Policy (SOP) and CORS
|
||||
|
||||
- **Same-Origin Policy**: Restricts documents or scripts from one origin interacting with resources from another origin.
|
||||
- **CORS** (Cross-Origin Resource Sharing): An HTTP-header mechanism allowing servers to permit cross-origin resource requests when needed.
|
||||
|
||||
### HTTP Communication Security
|
||||
|
||||
- **HTTPS/TLS**: Encrypts data during transport, preventing third-party interception.
|
||||
- **Certificate Transparency (CT)**: An open framework protecting against certificate misissuance through public logging.
|
||||
|
||||
### Secure Contexts and Feature Permissions
|
||||
|
||||
Browsers restrict "powerful features" (notifications, webcam, GPU, payments) to:
|
||||
|
||||
- Secure contexts (HTTPS/TLS delivery via `window` or `worker`).
|
||||
- Explicit user permission via the Permissions API.
|
||||
- User activation (transient activation -- requires user action like clicking).
|
||||
|
||||
## High-Level Security Considerations
|
||||
|
||||
### 1. Store Client-Side Data Responsibly
|
||||
|
||||
- Limit third-party cookie usage.
|
||||
- Prepare for removal of cross-site cookies.
|
||||
- Implement alternative persistence methods.
|
||||
|
||||
### 2. Protect User Identity and Manage Logins
|
||||
|
||||
- Use reputable frameworks with built-in security.
|
||||
- Implement **Multi-Factor Authentication (MFA)**.
|
||||
- Use dedicated APIs:
|
||||
- Web Authentication API
|
||||
- Federated Credential Management (FedCM) API
|
||||
|
||||
**Login Security Tips:**
|
||||
|
||||
- Enforce strong passwords.
|
||||
- Educate users about **phishing** attacks.
|
||||
- Implement **rate limiting** on login pages.
|
||||
- Use **CAPTCHA** challenges.
|
||||
- Manage sessions with unique session IDs.
|
||||
- Auto-logout after inactivity.
|
||||
|
||||
### 3. Do Not Include Sensitive Data in URL Query Strings
|
||||
|
||||
- Avoid GET requests with sensitive data (can be intercepted via the Referer header).
|
||||
- Use POST requests instead.
|
||||
- Protects against CSRF and replay attacks.
|
||||
|
||||
### 4. Enforce Usage Policies
|
||||
|
||||
- **Content Security Policy (CSP)**: Controls where images and scripts can be loaded from; mitigates XSS and data injection attacks.
|
||||
- **Permissions Policy**: Blocks access to specific "powerful features."
|
||||
|
||||
### 5. Maintain Data Integrity
|
||||
|
||||
- **Subresource Integrity (SRI)**: Crypto hash verification for fetched resources (from CDNs).
|
||||
- **MIME Type Verification**: Use the `X-Content-Type-Options` header to prevent MIME sniffing.
|
||||
- **Access-Control-Allow-Origin**: Manage cross-origin resource sharing.
|
||||
|
||||
### 6. Sanitize Form Input
|
||||
|
||||
- **Client-side validation**: Provide instant feedback using HTML form validation.
|
||||
- **Output encoding**: Safely display user input without executing it as code.
|
||||
- **Server-side validation**: Essential; client-side is easily bypassed.
|
||||
- **Escape special characters**: Prevent executable code injection (SQL injection, JavaScript execution).
|
||||
|
||||
### 7. Protect Against Clickjacking
|
||||
|
||||
- **X-Frame-Options**: HTTP header preventing page rendering in `<frame>`, `<iframe>`, `<embed>`, or `<object>`.
|
||||
- **CSP frame-ancestors**: Specifies valid parents that may embed a page.
|
||||
|
||||
## Common Security Attacks
|
||||
|
||||
| Attack | Description |
|
||||
|---|---|
|
||||
| Clickjacking | Tricks users into clicking hidden UI elements |
|
||||
| Cross-Site Scripting (XSS) | Injects malicious scripts into trusted websites |
|
||||
| Cross-Site Request Forgery (CSRF) | Forces authenticated users to perform unwanted actions |
|
||||
| Cross-Site Leaks (XS-Leaks) | Infers information about users from side channels |
|
||||
| SQL Injection | Inserts malicious SQL via user input |
|
||||
| Phishing | Impersonates trusted entities to steal credentials |
|
||||
| Man-in-the-Middle (MITM) | Intercepts communication between two parties |
|
||||
| Server-Side Request Forgery (SSRF) | Manipulates server into making unintended requests |
|
||||
| Subdomain Takeover | Exploits dangling DNS records |
|
||||
| Supply Chain Attacks | Compromises third-party dependencies |
|
||||
| Prototype Pollution | Injects properties into JavaScript object prototypes |
|
||||
|
||||
## Key HTTP Security Headers
|
||||
|
||||
| Header | Purpose |
|
||||
|---|---|
|
||||
| `Strict-Transport-Security` | Enforce HTTPS-only access |
|
||||
| `X-Frame-Options` | Prevent clickjacking |
|
||||
| `X-Content-Type-Options` | Prevent MIME sniffing |
|
||||
| `Content-Security-Policy` | Control resource loading and XSS prevention |
|
||||
| `Access-Control-Allow-Origin` | Manage CORS |
|
||||
|
||||
## Practical Implementation Guides
|
||||
|
||||
1. Content Security Policy (CSP)
|
||||
2. Cross-Origin Resource Sharing (CORS)
|
||||
3. Subresource Integrity (SRI)
|
||||
4. Transport Layer Security (TLS)
|
||||
5. Secure Cookie Configuration
|
||||
6. MIME Type Verification
|
||||
7. Referrer Policy
|
||||
8. Cross-Origin Resource Policy (CORP)
|
||||
|
||||
## Authentication Methods
|
||||
|
||||
- Passkeys
|
||||
- One-Time Passwords (OTP)
|
||||
- Federated identity
|
||||
- Password authentication
|
||||
|
||||
## Related Resources
|
||||
|
||||
- [Privacy on the Web](https://developer.mozilla.org/en-US/docs/Web/Privacy)
|
||||
- [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/)
|
||||
- [Mozilla Security Blog](https://blog.mozilla.org/security/)
|
||||
1643
skills/create-web-form/references/styling-web-forms.md
Normal file
1643
skills/create-web-form/references/styling-web-forms.md
Normal file
File diff suppressed because it is too large
Load Diff
165
skills/create-web-form/references/web-api.md
Normal file
165
skills/create-web-form/references/web-api.md
Normal file
@@ -0,0 +1,165 @@
|
||||
# Web API Reference
|
||||
|
||||
> Source: <https://developer.mozilla.org/en-US/docs/Web/API>
|
||||
|
||||
## Overview
|
||||
|
||||
Web APIs are programming interfaces available to developers for web applications, typically used with JavaScript. They enable building modern web applications with capabilities previously restricted to native apps (camera access, offline support, background processing, and more).
|
||||
|
||||
## API Categories
|
||||
|
||||
### Audio and Accessibility
|
||||
|
||||
- **Audio Output Devices API** -- Select audio output devices (Experimental).
|
||||
|
||||
### Background and Bluetooth
|
||||
|
||||
- **Background Fetch API** -- Manage long-running downloads.
|
||||
- **Background Synchronization API** -- Sync data in the background.
|
||||
- **Badging API** -- Display badges on app icons.
|
||||
- **Beacon API** -- Send analytics data.
|
||||
- **Web Bluetooth API** -- Connect to Bluetooth devices.
|
||||
|
||||
### Canvas, CSS, and Communication
|
||||
|
||||
- **Canvas API** -- 2D drawing on web pages.
|
||||
- **CSS APIs** (Painting, Font Loading, Typed Object Model).
|
||||
- **Clipboard API** -- Access clipboard data.
|
||||
- **Console API** -- Debugging tools.
|
||||
- **Cookie Store API** -- Manage cookies.
|
||||
- **Credential Management API** -- Handle authentication.
|
||||
|
||||
### DOM and Device
|
||||
|
||||
- **Document Object Model (DOM)** -- Core web API for manipulating page structure.
|
||||
- **Device Motion/Orientation Events** -- Access device sensors.
|
||||
- **Device Memory API** -- Detect device capabilities.
|
||||
|
||||
### Fetch and File System
|
||||
|
||||
- **Fetch API** -- Modern HTTP requests.
|
||||
- **File API** -- Access file data.
|
||||
- **File System API** -- Work with local files.
|
||||
- **Fullscreen API** -- Enter fullscreen mode.
|
||||
|
||||
### Geolocation and Graphics
|
||||
|
||||
- **Geolocation API** -- Get user location.
|
||||
- **Gamepad API** -- Connect game controllers.
|
||||
- **WebGL** -- 3D graphics rendering.
|
||||
- **WebGPU API** -- GPU computing.
|
||||
|
||||
### History and HTML
|
||||
|
||||
- **History API** -- Navigate browser history.
|
||||
- **HTML DOM API** -- Manipulate HTML elements.
|
||||
- **HTML Drag and Drop API** -- Native drag-and-drop support.
|
||||
|
||||
### Input and IndexedDB
|
||||
|
||||
- **IndexedDB API** -- Client-side structured database.
|
||||
- **Intersection Observer API** -- Track element visibility.
|
||||
|
||||
### Media and MediaStream
|
||||
|
||||
- **Media Capture and Streams API** -- Access camera and microphone.
|
||||
- **MediaStream Recording API** -- Record audio and video.
|
||||
- **Media Session API** -- Control playback.
|
||||
- **Media Source Extensions** -- Stream media content.
|
||||
|
||||
### Navigation and Network
|
||||
|
||||
- **Navigation API** -- Client-side routing.
|
||||
- **Network Information API** -- Detect connection type.
|
||||
|
||||
### Payment and Performance
|
||||
|
||||
- **Payment Request API** -- Checkout processing.
|
||||
- **Performance APIs** -- Monitor application performance.
|
||||
- **Permissions API** -- Request feature permissions.
|
||||
- **Picture-in-Picture API** -- Float video players.
|
||||
- **Pointer Events** -- Handle input devices.
|
||||
- **Push API** -- Receive push notifications.
|
||||
|
||||
### Storage and Sensors
|
||||
|
||||
- **Service Worker API** -- Offline functionality.
|
||||
- **Storage API** -- Persistent storage.
|
||||
- **Streams API** -- Work with data streams.
|
||||
- **Screen Capture API** -- Record screen content.
|
||||
|
||||
### Video and Virtual Reality
|
||||
|
||||
- **ViewTransition API** -- Animate page transitions.
|
||||
- **WebXR Device API** -- VR/AR experiences.
|
||||
|
||||
### WebSocket and Web Workers
|
||||
|
||||
- **WebSocket API** -- Real-time bidirectional communication.
|
||||
- **Web Workers API** -- Background processing.
|
||||
- **Web Audio API** -- Audio processing and synthesis.
|
||||
- **Web Authentication API** -- WebAuthn support.
|
||||
- **Web Storage API** -- `localStorage` and `sessionStorage`.
|
||||
|
||||
### XML
|
||||
|
||||
- **XMLHttpRequest API** -- Legacy HTTP requests (largely superseded by Fetch).
|
||||
|
||||
## Key Interface Examples
|
||||
|
||||
### Core DOM Interfaces
|
||||
|
||||
```javascript
|
||||
Document, Element, HTMLElement
|
||||
Node, NodeList
|
||||
DocumentFragment
|
||||
Attr, NamedNodeMap
|
||||
```
|
||||
|
||||
### Event Handling
|
||||
|
||||
```javascript
|
||||
Event, EventTarget, CustomEvent
|
||||
MouseEvent, KeyboardEvent, TouchEvent
|
||||
PointerEvent, DragEvent
|
||||
```
|
||||
|
||||
### Async Operations
|
||||
|
||||
```javascript
|
||||
// Promise-based APIs
|
||||
AbortController, AbortSignal
|
||||
Fetch, Request, Response
|
||||
```
|
||||
|
||||
### Media and Graphics
|
||||
|
||||
```javascript
|
||||
HTMLMediaElement, AudioContext
|
||||
Canvas, CanvasRenderingContext2D
|
||||
WebGL2RenderingContext, GPU
|
||||
```
|
||||
|
||||
### Storage and Databases
|
||||
|
||||
```javascript
|
||||
Storage // localStorage, sessionStorage
|
||||
IndexedDB // IDBDatabase, IDBTransaction
|
||||
CacheStorage // Service Worker caching
|
||||
```
|
||||
|
||||
## Key Concepts
|
||||
|
||||
1. **Progressive Enhancement** -- APIs gracefully degrade on older browsers.
|
||||
2. **Standards-based** -- Follow W3C and WHATWG specifications.
|
||||
3. **Experimental APIs** -- Marked for features still in development; may change or be removed.
|
||||
4. **Deprecated APIs** -- Legacy features being phased out; avoid in new projects.
|
||||
5. **Non-standard APIs** -- Browser-specific implementations; use with caution.
|
||||
|
||||
## Important Notes
|
||||
|
||||
- Web APIs are typically used with JavaScript but are not limited to it.
|
||||
- Many APIs require **user permission** (Geolocation, Camera, Microphone).
|
||||
- Some APIs are **experimental** and may change or be removed.
|
||||
- Browser support varies by API -- always check compatibility before use.
|
||||
- Older deprecated APIs should be avoided in new projects.
|
||||
974
skills/create-web-form/references/web-performance.md
Normal file
974
skills/create-web-form/references/web-performance.md
Normal file
@@ -0,0 +1,974 @@
|
||||
# Web Performance Reference
|
||||
|
||||
A consolidated reference guide covering web performance concepts, optimization techniques, and the Performance API, sourced from the Mozilla Developer Network (MDN).
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Web Performance Overview](#1-web-performance-overview)
|
||||
2. [Performance Fundamentals](#2-performance-fundamentals)
|
||||
3. [Performance Best Practices](#3-performance-best-practices)
|
||||
4. [HTML Performance](#4-html-performance)
|
||||
5. [JavaScript Performance](#5-javascript-performance)
|
||||
6. [CSS Performance](#6-css-performance)
|
||||
7. [Performance API](#7-performance-api)
|
||||
8. [Performance Data](#8-performance-data)
|
||||
9. [Server Timing](#9-server-timing)
|
||||
10. [User Timing](#10-user-timing)
|
||||
|
||||
---
|
||||
|
||||
## 1. Web Performance Overview
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/Performance>
|
||||
|
||||
### Definition
|
||||
|
||||
**Web performance** encompasses:
|
||||
|
||||
- Objective measurements (load time, frames per second, time to interactive)
|
||||
- Perceived user experience of load and response times
|
||||
- Smoothness during user interactions (scrolling, animations, button responsiveness)
|
||||
|
||||
### Recommended Timings
|
||||
|
||||
| Target | Threshold |
|
||||
|--------|-----------|
|
||||
| Page load indication | 1 second |
|
||||
| Idling | 50ms |
|
||||
| Animations | 16.7ms (60 FPS) |
|
||||
| User input response | 50-200ms |
|
||||
|
||||
Users abandon sites that respond slowly. The goal is to minimize loading and response times while adding features that conceal latency by maximizing availability and interactivity as soon as possible.
|
||||
|
||||
### Key Performance Metrics
|
||||
|
||||
| Metric | Full Name | Definition |
|
||||
|--------|-----------|------------|
|
||||
| **FCP** | First Contentful Paint | First time any content appears |
|
||||
| **LCP** | Largest Contentful Paint | Largest content element visible |
|
||||
| **CLS** | Cumulative Layout Shift | Visual stability during interactions |
|
||||
| **INP** | Interaction to Next Paint | Responsiveness to user input |
|
||||
| **TTFB** | Time to First Byte | Server response time |
|
||||
| **TTI** | Time to Interactive | Page becomes fully interactive |
|
||||
| **Jank** | -- | Non-smooth animation or scrolling |
|
||||
|
||||
### Performance API Categories
|
||||
|
||||
- **High-precision timing**: Sub-millisecond monitoring via stable monotonic clock
|
||||
- **Navigation Timing**: Metrics for page navigation (DOMContentLoaded, load time)
|
||||
- **Resource Timing**: Detailed network timing for individual resources
|
||||
- **User Timing**: Custom marks and measures
|
||||
- **Long Animation Frames (LoAF)**: Identifies janky animations
|
||||
- **Server Timing**: Backend performance metrics
|
||||
|
||||
### Related Browser APIs
|
||||
|
||||
- **Page Visibility API**: Track document visibility state
|
||||
- **Background Tasks API** (`requestIdleCallback()`): Queue non-blocking tasks
|
||||
- **Intersection Observer API**: Asynchronously monitor element visibility
|
||||
- **Network Information API**: Detect connection type for adaptive content
|
||||
- **Battery Status API**: Optimize for power-constrained devices
|
||||
- **Beacon API**: Send performance data to analytics
|
||||
- **Media Capabilities API**: Check device media support
|
||||
|
||||
### Resource Loading Hints
|
||||
|
||||
- **DNS-prefetch**: Pre-resolve domain names
|
||||
- **Preconnect**: Establish early connections
|
||||
- **Prefetch**: Load resources before needed
|
||||
- **Preload**: Load critical resources early
|
||||
|
||||
### Monitoring Approaches
|
||||
|
||||
- **Real User Monitoring (RUM)**: Long-term trend analysis from actual users
|
||||
- **Synthetic Monitoring**: Controlled regression testing during development
|
||||
|
||||
---
|
||||
|
||||
## 2. Performance Fundamentals
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Performance>
|
||||
|
||||
### Why Web Performance Matters
|
||||
|
||||
- Promotes accessibility and inclusive design
|
||||
- Enhances user experience and retention
|
||||
- Directly impacts business goals and conversions
|
||||
|
||||
### Core Components
|
||||
|
||||
- Web page loading performance
|
||||
- Content rendering in browsers
|
||||
- User agent capabilities and constraints
|
||||
- Performance across different user groups
|
||||
|
||||
### Perceived Performance
|
||||
|
||||
Metrics focused on user perception rather than raw milliseconds:
|
||||
|
||||
- **Page load time** -- initial content availability
|
||||
- **Responsiveness** -- interaction feedback speed
|
||||
- **Animation smoothness** -- visual fluidity
|
||||
- **Scrolling smoothness** -- scroll interaction quality
|
||||
|
||||
### Optimization Areas
|
||||
|
||||
| Area | Focus | Impact |
|
||||
|------|-------|--------|
|
||||
| **Multimedia (Images)** | Media optimization based on device capability, size, pixel density | Reduces bytes per image |
|
||||
| **Multimedia (Video)** | Video compression, audio track removal from background videos | Reduces file size |
|
||||
| **JavaScript** | Best practices for interactive experiences | Improves responsiveness, battery life |
|
||||
| **HTML** | DOM node minimization, optimal attribute ordering | Improves load and render time |
|
||||
| **CSS** | Feature-specific optimization | Prevents negative performance impact |
|
||||
|
||||
### Performance Strategy
|
||||
|
||||
- **Performance budgets**: Set limits on asset sizes
|
||||
- **Performance culture**: Organizational commitment
|
||||
- **Regression prevention**: Avoid bloat over time
|
||||
- **Mobile-first approaches**: Responsive images and adaptive media delivery
|
||||
|
||||
---
|
||||
|
||||
## 3. Performance Best Practices
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Performance/Best_practices>
|
||||
|
||||
### Core Best Practices
|
||||
|
||||
1. **Learn the Critical Rendering Path** -- Understand how browsers render pages to optimize performance
|
||||
2. **Use Resource Hints** -- `rel=preconnect`, `rel=dns-prefetch`, `rel=prefetch`, `rel=preload`
|
||||
3. **Minimize JavaScript** -- Only load JavaScript needed for the current page
|
||||
4. **Optimize CSS** -- Address CSS performance factors, load CSS asynchronously when possible
|
||||
5. **Use HTTP/2** -- Deploy HTTP/2 on your server or CDN
|
||||
6. **Use a CDN** -- Significantly reduces resource load times
|
||||
7. **Compress Resources** -- Use gzip, Brotli, or Zopfli compression
|
||||
8. **Optimize Images** -- Use CSS animations or SVG when possible
|
||||
9. **Implement Lazy Loading** -- Load content outside viewport lazily; use the `loading` attribute on `<img>` elements
|
||||
10. **Focus on User Perception** -- Perceived performance matters as much as actual timing
|
||||
|
||||
### Asynchronous CSS Loading
|
||||
|
||||
```html
|
||||
<link
|
||||
id="my-stylesheet"
|
||||
rel="stylesheet"
|
||||
href="/path/to/my.css"
|
||||
media="print" />
|
||||
<noscript><link rel="stylesheet" href="/path/to/my.css" /></noscript>
|
||||
```
|
||||
|
||||
```javascript
|
||||
const stylesheet = document.getElementById("my-stylesheet");
|
||||
stylesheet.addEventListener("load", () => {
|
||||
stylesheet.media = "all";
|
||||
});
|
||||
```
|
||||
|
||||
### Critical CSS Inlining
|
||||
|
||||
- Inline CSS for above-the-fold content using `<style>` tags
|
||||
- Prevents Flash of Unstyled Text (FOUT)
|
||||
- Improves perceived performance
|
||||
|
||||
### JavaScript Loading
|
||||
|
||||
- Use `async` or `defer` attributes on script tags
|
||||
- JavaScript only blocks rendering for elements after the script tag in the DOM
|
||||
|
||||
### Web Font Best Practices
|
||||
|
||||
1. **Font Format Selection**: Use WOFF and WOFF2 (built-in compression); compress EOT and TTF with gzip or Brotli
|
||||
2. **Font Loading Strategy**: Use `font-display: swap` to prevent rendering blocks; optimize `font-weight` to match the web font closely
|
||||
3. **Avoid Icon Fonts**: Use compressed SVG instead; inline SVG data in HTML to avoid additional HTTP requests
|
||||
|
||||
### Tools and Measurement
|
||||
|
||||
- [Firefox Dev Tools](https://firefox-source-docs.mozilla.org/devtools-user/performance/index.html)
|
||||
- [PageSpeed Insights](https://pagespeed.web.dev/)
|
||||
- [Lighthouse](https://developer.chrome.com/docs/lighthouse/overview/)
|
||||
- [WebPageTest.org](https://www.webpagetest.org/)
|
||||
- [Chrome User Experience Report](https://developer.chrome.com/docs/crux/)
|
||||
- `window.performance.timing` (native Performance API)
|
||||
|
||||
### Practices to Avoid
|
||||
|
||||
- Downloading everything unnecessarily
|
||||
- Using uncompressed media files
|
||||
|
||||
---
|
||||
|
||||
## 4. HTML Performance
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Performance/HTML>
|
||||
|
||||
### Main HTML-Related Performance Bottlenecks
|
||||
|
||||
- Image and video file sizes (replaced elements)
|
||||
- Embedded content delivery (`<iframe>` elements)
|
||||
- Resource loading order
|
||||
|
||||
### Responsive Image Handling
|
||||
|
||||
**Using `srcset` and `sizes` for different screen widths:**
|
||||
|
||||
```html
|
||||
<img
|
||||
srcset="480w.jpg 480w, 800w.jpg 800w"
|
||||
sizes="(width <= 600px) 480px, 800px"
|
||||
src="800w.jpg"
|
||||
alt="Family portrait" />
|
||||
```
|
||||
|
||||
**Using `srcset` for different device resolutions:**
|
||||
|
||||
```html
|
||||
<img
|
||||
srcset="320w.jpg, 480w.jpg 1.5x, 640w.jpg 2x"
|
||||
src="640w.jpg"
|
||||
alt="Family portrait" />
|
||||
```
|
||||
|
||||
**Using the `<picture>` element:**
|
||||
|
||||
```html
|
||||
<picture>
|
||||
<source media="(width < 800px)" srcset="narrow-banner-480w.jpg" />
|
||||
<source media="(width >= 800px)" srcset="wide-banner-800w.jpg" />
|
||||
<img src="large-banner-800w.jpg" alt="Dense forest scene" />
|
||||
</picture>
|
||||
```
|
||||
|
||||
### Lazy Loading
|
||||
|
||||
**Images:**
|
||||
|
||||
```html
|
||||
<img src="800w.jpg" alt="Family portrait" loading="lazy" />
|
||||
```
|
||||
|
||||
**Video (disable preload):**
|
||||
|
||||
```html
|
||||
<video controls preload="none" poster="poster.jpg">
|
||||
<source src="video.webm" type="video/webm" />
|
||||
<source src="video.mp4" type="video/mp4" />
|
||||
</video>
|
||||
```
|
||||
|
||||
**Iframes:**
|
||||
|
||||
```html
|
||||
<iframe src="https://example.com" loading="lazy" width="600" height="400"></iframe>
|
||||
```
|
||||
|
||||
### Iframe Best Practices
|
||||
|
||||
Avoid embedded `<iframe>` elements unless absolutely necessary. Problems include:
|
||||
|
||||
- Extra HTTP requests required
|
||||
- Creates a separate page instance (expensive)
|
||||
- Cannot share cached assets
|
||||
- Separate CSS and JavaScript handling required
|
||||
|
||||
**Alternative:** Use `fetch()` and DOM scripting to load content into the same page.
|
||||
|
||||
### JavaScript Loading in HTML
|
||||
|
||||
**`async` attribute** -- fetches in parallel with DOM parsing, does not block rendering:
|
||||
|
||||
```html
|
||||
<script async src="index.js"></script>
|
||||
```
|
||||
|
||||
**`defer` attribute** -- executes after document parsing but before `DOMContentLoaded` event.
|
||||
|
||||
**Module loading** -- split code into modules and load parts as needed.
|
||||
|
||||
### Resource Preloading
|
||||
|
||||
```html
|
||||
<link rel="preload" href="sintel-short.mp4" as="video" type="video/mp4" />
|
||||
```
|
||||
|
||||
Other `rel` attributes for performance:
|
||||
|
||||
- `rel="dns-prefetch"` -- prefetch DNS lookups
|
||||
- `rel="preconnect"` -- pre-establish connections
|
||||
- `rel="modulepreload"` -- preload JavaScript modules
|
||||
- `rel="prefetch"` -- load resources for future navigation
|
||||
|
||||
### Resource Loading Order
|
||||
|
||||
1. **HTML** is parsed first in source order
|
||||
2. **CSS** is parsed; linked assets (images, fonts) start fetching
|
||||
3. **JavaScript** is parsed and executed (blocks subsequent HTML parsing by default)
|
||||
4. **Styling** is computed for HTML elements
|
||||
5. **Rendering** of styled content to the screen
|
||||
|
||||
### Key Takeaway
|
||||
|
||||
HTML is simple and fast by default. Focus on:
|
||||
|
||||
- Minimizing bytes downloaded (images and videos)
|
||||
- Controlling asset loading order (async, defer, preload)
|
||||
- Reducing unnecessary embedded content (iframes)
|
||||
- Responsive serving of replaced elements (srcset, picture, media queries)
|
||||
|
||||
HTML file size minification provides negligible benefits compared to optimizing media assets.
|
||||
|
||||
---
|
||||
|
||||
## 5. JavaScript Performance
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Performance/JavaScript>
|
||||
|
||||
### Core Principle
|
||||
|
||||
**Measure first.** Use browser network and performance tools to identify what actually needs optimizing before implementing techniques.
|
||||
|
||||
### Optimizing Downloads
|
||||
|
||||
- **Use minimal JavaScript** -- avoid frameworks for static experiences
|
||||
- **Remove unused code** -- delete functionality not being used
|
||||
- **Leverage built-in browser features**: built-in form validation, native `<video>` players, CSS animations instead of JavaScript libraries
|
||||
- **Minification** -- reduces file character count and bytes
|
||||
- **Compression** -- gzip (standard) or Brotli (generally outperforms gzip)
|
||||
- **Module bundlers** -- use webpack for optimization and code splitting
|
||||
|
||||
### Loading Critical Assets Early
|
||||
|
||||
```html
|
||||
<!-- Preload standard JavaScript -->
|
||||
<link rel="preload" href="important-js.js" as="script" />
|
||||
|
||||
<!-- Preload JavaScript module -->
|
||||
<link rel="modulepreload" href="important-module.js" />
|
||||
```
|
||||
|
||||
### Deferring Non-Critical JavaScript
|
||||
|
||||
**Async:**
|
||||
|
||||
```html
|
||||
<script async src="main.js"></script>
|
||||
```
|
||||
|
||||
**Defer:**
|
||||
|
||||
```html
|
||||
<script defer src="main.js"></script>
|
||||
```
|
||||
|
||||
**Dynamic loading:**
|
||||
|
||||
```javascript
|
||||
const scriptElem = document.createElement("script");
|
||||
scriptElem.src = "index.js";
|
||||
scriptElem.addEventListener("load", () => {
|
||||
init();
|
||||
});
|
||||
document.head.append(scriptElem);
|
||||
```
|
||||
|
||||
**Dynamic module import:**
|
||||
|
||||
```javascript
|
||||
import("./modules/myModule.js").then((module) => {
|
||||
// Use the loaded module
|
||||
});
|
||||
```
|
||||
|
||||
### Breaking Down Long Tasks
|
||||
|
||||
Tasks taking more than 50ms are "long tasks" that block the main thread. Use task yielding:
|
||||
|
||||
```javascript
|
||||
function yieldFunc() {
|
||||
if ("scheduler" in window && "yield" in scheduler) {
|
||||
return scheduler.yield();
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, 0);
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const tasks = [a, b, c, d, e];
|
||||
while (tasks.length > 0) {
|
||||
const task = tasks.shift();
|
||||
task();
|
||||
await yieldFunc();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Animation Best Practices
|
||||
|
||||
- Reduce non-essential animations
|
||||
- Provide an opt-out for users on low-power devices
|
||||
- Prefer CSS animations over JavaScript (much faster and more efficient)
|
||||
- For canvas animations, use `requestAnimationFrame()`:
|
||||
|
||||
```javascript
|
||||
function loop() {
|
||||
ctx.fillStyle = "rgb(0 0 0 / 25%)";
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
for (const ball of balls) {
|
||||
ball.draw();
|
||||
ball.update();
|
||||
}
|
||||
requestAnimationFrame(loop);
|
||||
}
|
||||
loop();
|
||||
```
|
||||
|
||||
### Event Performance
|
||||
|
||||
- Remove unnecessary event listeners with `removeEventListener()`
|
||||
- Use event delegation (single listener on parent instead of multiple on children):
|
||||
|
||||
```javascript
|
||||
parent.addEventListener("click", (event) => {
|
||||
if (event.target.matches(".child")) {
|
||||
// Handle child click
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Efficient Code Patterns
|
||||
|
||||
**Batch DOM changes:**
|
||||
|
||||
```javascript
|
||||
const fragment = document.createDocumentFragment();
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const li = document.createElement("li");
|
||||
li.textContent = items[i];
|
||||
fragment.appendChild(li);
|
||||
}
|
||||
ul.appendChild(fragment); // Single DOM operation
|
||||
```
|
||||
|
||||
**Exit loops early:**
|
||||
|
||||
```javascript
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
if (array[i] === toFind) {
|
||||
processMatchingArray(array);
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Move work outside loops:**
|
||||
|
||||
```javascript
|
||||
// Fetch once, iterate in-memory
|
||||
const response = await fetch(`/results?number=${number}`);
|
||||
const results = await response.json();
|
||||
for (let i = 0; i < number; i++) {
|
||||
processResult(results[i]);
|
||||
}
|
||||
```
|
||||
|
||||
### Offload Computation
|
||||
|
||||
- **Asynchronous JavaScript** -- `async`/`await` for non-blocking I/O
|
||||
- **Web Workers** -- offload heavy computation to a separate thread
|
||||
- **WebGPU** -- use the system GPU for high-performance computations
|
||||
|
||||
---
|
||||
|
||||
## 6. CSS Performance
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Performance/CSS>
|
||||
|
||||
### Rendering and CSSOM Optimization
|
||||
|
||||
**Remove unnecessary styles:**
|
||||
|
||||
- Parse only used CSS rules
|
||||
- Clean up unused styles added during development
|
||||
|
||||
**Split CSS into separate modules:**
|
||||
|
||||
```html
|
||||
<!-- Render-blocking -->
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
|
||||
<!-- Non-blocking with media queries -->
|
||||
<link rel="stylesheet" href="print.css" media="print" />
|
||||
<link rel="stylesheet" href="mobile.css" media="screen and (width <= 480px)" />
|
||||
```
|
||||
|
||||
**Minify and compress CSS** as part of the build process with gzip compression on servers.
|
||||
|
||||
**Simplify selectors:**
|
||||
|
||||
```css
|
||||
/* Avoid overly complex selectors */
|
||||
body div#main-content article.post h2.headline {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
/* Prefer simple selectors */
|
||||
.headline {
|
||||
font-size: 24px;
|
||||
}
|
||||
```
|
||||
|
||||
**Avoid universal over-application:**
|
||||
|
||||
```css
|
||||
/* Problematic */
|
||||
body * {
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
}
|
||||
```
|
||||
|
||||
**Reduce HTTP requests with CSS sprites** -- combine multiple small images into one file and use `background-position`.
|
||||
|
||||
**Preload critical assets:**
|
||||
|
||||
```html
|
||||
<link rel="preload" href="style.css" as="style" />
|
||||
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin />
|
||||
```
|
||||
|
||||
### Animation Performance
|
||||
|
||||
**Properties that cause reflow/repaint (avoid animating):**
|
||||
|
||||
- Dimensions: `width`, `height`, `border`, `padding`
|
||||
- Position: `margin`, `top`, `bottom`, `left`, `right`
|
||||
- Layout: `align-content`, `align-items`, `flex`
|
||||
- Visual effects: `box-shadow`
|
||||
|
||||
**Safe properties to animate (GPU-accelerated):**
|
||||
|
||||
- `transform`
|
||||
- `opacity`
|
||||
- `filter`
|
||||
|
||||
**Respect user preferences:**
|
||||
|
||||
```css
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
* {
|
||||
animation: none !important;
|
||||
transition: none !important;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Advanced Optimization
|
||||
|
||||
**`will-change` property** (use as a last resort only):
|
||||
|
||||
```css
|
||||
.element {
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
```
|
||||
|
||||
**CSS Containment:**
|
||||
|
||||
```css
|
||||
article {
|
||||
contain: content;
|
||||
}
|
||||
```
|
||||
|
||||
**`content-visibility` (skip rendering until needed):**
|
||||
|
||||
```css
|
||||
article {
|
||||
content-visibility: auto;
|
||||
contain-intrinsic-size: 1000px;
|
||||
}
|
||||
```
|
||||
|
||||
### Font Performance
|
||||
|
||||
**Load important fonts early:**
|
||||
|
||||
```html
|
||||
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin />
|
||||
```
|
||||
|
||||
**Load only required glyphs:**
|
||||
|
||||
```css
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
src: url("font.woff2") format("woff2");
|
||||
unicode-range: U+0025-00FF;
|
||||
}
|
||||
```
|
||||
|
||||
**Define font display behavior:**
|
||||
|
||||
```css
|
||||
@font-face {
|
||||
font-family: "someFont";
|
||||
src: url("font.woff") format("woff");
|
||||
font-display: fallback;
|
||||
}
|
||||
```
|
||||
|
||||
**Font tips:**
|
||||
|
||||
- Use only 2-3 fonts maximum
|
||||
- Prefer web-safe fonts when possible
|
||||
- Consider `rel="preconnect"` for third-party font providers
|
||||
|
||||
---
|
||||
|
||||
## 7. Performance API
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/API/Performance_API>
|
||||
|
||||
### Overview
|
||||
|
||||
The Performance API is a group of standards used to measure web application performance. It provides built-in metrics and enables developers to add custom measurements to the browser's performance timeline with high-precision timestamps.
|
||||
|
||||
Available in both `Window` and `Worker` global scopes via `Window.performance` and `WorkerGlobalScope.performance`.
|
||||
|
||||
### Core Concepts
|
||||
|
||||
Each performance metric is represented by a `PerformanceEntry` with: `name`, `duration`, `startTime`, and `type`.
|
||||
|
||||
Most entries are automatically recorded and accessible via:
|
||||
|
||||
- `Performance.getEntries()`
|
||||
- `PerformanceObserver` (preferred method)
|
||||
|
||||
### Main Interfaces
|
||||
|
||||
**Performance Management:**
|
||||
|
||||
- `Performance` -- main interface for accessing performance measurements
|
||||
- `PerformanceEntry` -- base interface for all performance metrics
|
||||
- `PerformanceObserver` -- listens for new performance entries as they are recorded
|
||||
|
||||
**Custom Measurements:**
|
||||
|
||||
- `PerformanceMark` -- custom markers on the performance timeline
|
||||
- `PerformanceMeasure` -- custom measurements between two entries
|
||||
|
||||
**Built-in Metrics:**
|
||||
|
||||
| Interface | Purpose |
|
||||
|-----------|---------|
|
||||
| `PerformanceNavigationTiming` | Document navigation timings (load time, etc.) |
|
||||
| `PerformanceResourceTiming` | Network metrics for resources (images, scripts, CSS, fetch calls) |
|
||||
| `PerformancePaintTiming` | Render operations during page construction |
|
||||
| `PerformanceEventTiming` | Event latency and Interaction to Next Paint (INP) |
|
||||
| `LargestContentfulPaint` | Render time of largest visible content |
|
||||
| `LayoutShift` | Page layout stability metrics |
|
||||
| `PerformanceLongTaskTiming` | Long-running tasks blocking rendering |
|
||||
| `PerformanceLongAnimationFrameTiming` | Long animation frame metrics |
|
||||
| `PerformanceServerTiming` | Server metrics from `Server-Timing` HTTP header |
|
||||
|
||||
### Usage Pattern
|
||||
|
||||
```javascript
|
||||
// Using PerformanceObserver (recommended)
|
||||
const observer = new PerformanceObserver((list) => {
|
||||
for (const entry of list.getEntries()) {
|
||||
console.log(`${entry.name}: ${entry.duration}ms`);
|
||||
}
|
||||
});
|
||||
observer.observe({ entryTypes: ["navigation", "resource", "paint"] });
|
||||
|
||||
// Custom measurements
|
||||
performance.mark("start-operation");
|
||||
// ... perform work ...
|
||||
performance.mark("end-operation");
|
||||
performance.measure("operation-duration", "start-operation", "end-operation");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Performance Data
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/API/Performance_API/Performance_data>
|
||||
|
||||
### Types of Performance Entries
|
||||
|
||||
| Entry Type | Interface | Purpose |
|
||||
|------------|-----------|---------|
|
||||
| `"element"` | PerformanceElementTiming | Load and render time for specific DOM elements |
|
||||
| `"event"` | PerformanceEventTiming | Browser response time to event triggers |
|
||||
| `"first-input"` | PerformanceEventTiming | First Input Delay measurement |
|
||||
| `"largest-contentful-paint"` | LargestContentfulPaint | Largest paint during page load |
|
||||
| `"layout-shift"` | LayoutShift | Page layout shift metrics |
|
||||
| `"longtask"` | PerformanceLongTaskTiming | Tasks taking 50ms or more |
|
||||
| `"mark"` | PerformanceMark | Custom developer timestamps |
|
||||
| `"measure"` | PerformanceMeasure | Custom measurements between timestamps |
|
||||
| `"navigation"` | PerformanceNavigationTiming | Navigation and initial page load metrics |
|
||||
| `"paint"` | PerformancePaintTiming | Key rendering moments during page load |
|
||||
| `"resource"` | PerformanceResourceTiming | Resource fetch duration |
|
||||
| `"visibility-state"` | VisibilityStateEntry | Tab visibility state changes |
|
||||
|
||||
### Accessing Performance Data
|
||||
|
||||
**Method 1: PerformanceObserver (preferred)**
|
||||
|
||||
```javascript
|
||||
function logEventDuration(entries) {
|
||||
const events = entries.getEntriesByType("event");
|
||||
for (const event of events) {
|
||||
console.log(
|
||||
`Event handler took: ${event.processingEnd - event.processingStart} milliseconds`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const observer = new PerformanceObserver(logEventDuration);
|
||||
observer.observe({ type: "event", buffered: true });
|
||||
```
|
||||
|
||||
Advantages of PerformanceObserver:
|
||||
|
||||
- Automatically filters duplicate entries
|
||||
- Asynchronous delivery during idle time
|
||||
- Required for some entry types
|
||||
- Lower performance impact
|
||||
|
||||
**Method 2: Direct query methods**
|
||||
|
||||
```javascript
|
||||
performance.getEntries(); // All entries
|
||||
performance.getEntriesByType(type); // Entries of specific type
|
||||
performance.getEntriesByName(name); // Entries with specific name
|
||||
```
|
||||
|
||||
### Performance Entry Buffer Sizes
|
||||
|
||||
| Entry Type | Max Buffer Size |
|
||||
|------------|----------------|
|
||||
| `"resource"` | 250 (adjustable) |
|
||||
| `"longtask"` | 200 |
|
||||
| `"element"` | 150 |
|
||||
| `"event"` | 150 |
|
||||
| `"layout-shift"` | 150 |
|
||||
| `"largest-contentful-paint"` | 150 |
|
||||
| `"visibility-state"` | 50 |
|
||||
| `"mark"` | Infinite |
|
||||
| `"measure"` | Infinite |
|
||||
| `"navigation"` | Infinite |
|
||||
| `"paint"` | 2 (fixed) |
|
||||
| `"first-input"` | 1 (fixed) |
|
||||
|
||||
### Handling Dropped Entries
|
||||
|
||||
```javascript
|
||||
function perfObserver(list, observer, droppedEntriesCount) {
|
||||
list.getEntries().forEach((entry) => {
|
||||
// process entries
|
||||
});
|
||||
if (droppedEntriesCount > 0) {
|
||||
console.warn(
|
||||
`${droppedEntriesCount} entries were dropped because the buffer was full.`
|
||||
);
|
||||
}
|
||||
}
|
||||
const observer = new PerformanceObserver(perfObserver);
|
||||
observer.observe({ type: "resource", buffered: true });
|
||||
```
|
||||
|
||||
### JSON Serialization
|
||||
|
||||
All performance entries provide a `toJSON()` method:
|
||||
|
||||
```javascript
|
||||
const observer = new PerformanceObserver((list) => {
|
||||
list.getEntries().forEach((entry) => {
|
||||
console.log(entry.toJSON());
|
||||
});
|
||||
});
|
||||
observer.observe({ type: "event", buffered: true });
|
||||
```
|
||||
|
||||
### Opt-In Metrics
|
||||
|
||||
Some metrics require explicit configuration:
|
||||
|
||||
- **Element Timing** -- add `elementtiming` attribute to elements
|
||||
- **User Timing** -- call Performance API methods at relevant points
|
||||
- **Server Timing** -- server sends `Server-Timing` HTTP header
|
||||
|
||||
---
|
||||
|
||||
## 9. Server Timing
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/API/Performance_API/Server_timing>
|
||||
|
||||
### What is Server Timing?
|
||||
|
||||
Server Timing is part of the Performance API and allows servers to communicate metrics about the request-response cycle to the user agent. It surfaces backend server timing metrics such as database read/write times, CPU time, and file system access.
|
||||
|
||||
### Server-Timing HTTP Header Examples
|
||||
|
||||
```http
|
||||
// Single metric without value
|
||||
Server-Timing: missedCache
|
||||
|
||||
// Single metric with value
|
||||
Server-Timing: cpu;dur=2.4
|
||||
|
||||
// Single metric with description and value
|
||||
Server-Timing: cache;desc="Cache Read";dur=23.2
|
||||
|
||||
// Two metrics with values
|
||||
Server-Timing: db;dur=53, app;dur=47.2
|
||||
|
||||
// Server-Timing as trailer
|
||||
Trailer: Server-Timing
|
||||
--- response body ---
|
||||
Server-Timing: total;dur=123.4
|
||||
```
|
||||
|
||||
### Retrieving Server Metrics in JavaScript
|
||||
|
||||
Server timing metrics are stored as `PerformanceServerTiming` entries, accessed within `"navigation"` and `"resource"` performance entries via the `PerformanceResourceTiming.serverTiming` property.
|
||||
|
||||
```javascript
|
||||
const observer = new PerformanceObserver((list) => {
|
||||
list.getEntries().forEach((entry) => {
|
||||
entry.serverTiming.forEach((serverEntry) => {
|
||||
console.log(
|
||||
`${serverEntry.name} (${serverEntry.description}) duration: ${serverEntry.duration}`
|
||||
);
|
||||
// Logs "cache (Cache Read) duration: 23.2"
|
||||
// Logs "db () duration: 53"
|
||||
// Logs "app () duration: 47.2"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
["navigation", "resource"].forEach((type) =>
|
||||
observer.observe({ type, buffered: true })
|
||||
);
|
||||
```
|
||||
|
||||
### Privacy and Security Considerations
|
||||
|
||||
- The `Server-Timing` header may expose sensitive application and infrastructure information; metrics should only be returned to authenticated users
|
||||
- `PerformanceServerTiming` is restricted to the same origin by default
|
||||
- Use the `Timing-Allow-Origin` header to specify allowed cross-origin domains
|
||||
- Only available in secure contexts (HTTPS) in some browsers
|
||||
- There is no clock synchronization between server, client, and intermediate proxies; server timestamps may not meaningfully map to the client timeline `startTime`
|
||||
|
||||
---
|
||||
|
||||
## 10. User Timing
|
||||
|
||||
> **Source:** <https://developer.mozilla.org/en-US/docs/Web/API/Performance_API/User_timing>
|
||||
|
||||
### Overview
|
||||
|
||||
User Timing is part of the Performance API and allows you to measure application performance using high-precision timestamps. It consists of two main components:
|
||||
|
||||
- **`PerformanceMark`** entries -- named marks at any location in an application
|
||||
- **`PerformanceMeasure`** entries -- time measurements between two marks
|
||||
|
||||
### Adding Performance Markers
|
||||
|
||||
```javascript
|
||||
// Basic marks
|
||||
performance.mark("login-started");
|
||||
performance.mark("login-finished");
|
||||
|
||||
// Advanced mark with options
|
||||
performance.mark("login-started", {
|
||||
startTime: 12.5,
|
||||
detail: { htmlElement: myElement.id },
|
||||
});
|
||||
```
|
||||
|
||||
### Measuring Duration Between Markers
|
||||
|
||||
```javascript
|
||||
const loginMeasure = performance.measure(
|
||||
"login-duration",
|
||||
"login-started",
|
||||
"login-finished"
|
||||
);
|
||||
console.log(loginMeasure.duration);
|
||||
```
|
||||
|
||||
**Advanced measurement from an event timestamp to a mark:**
|
||||
|
||||
```javascript
|
||||
loginButton.addEventListener("click", (clickEvent) => {
|
||||
fetch(loginURL).then((data) => {
|
||||
renderLoggedInUser(data);
|
||||
const marker = performance.mark("login-finished");
|
||||
performance.measure("login-click", {
|
||||
detail: { htmlElement: myElement.id },
|
||||
start: clickEvent.timeStamp,
|
||||
end: marker.startTime,
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Observing Performance Measures
|
||||
|
||||
```javascript
|
||||
function perfObserver(list, observer) {
|
||||
list.getEntries().forEach((entry) => {
|
||||
if (entry.entryType === "mark") {
|
||||
console.log(`${entry.name}'s startTime: ${entry.startTime}`);
|
||||
}
|
||||
if (entry.entryType === "measure") {
|
||||
console.log(`${entry.name}'s duration: ${entry.duration}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
const observer = new PerformanceObserver(perfObserver);
|
||||
observer.observe({ entryTypes: ["measure", "mark"] });
|
||||
```
|
||||
|
||||
### Retrieving Markers and Measures
|
||||
|
||||
```javascript
|
||||
// All entries
|
||||
const entries = performance.getEntries();
|
||||
|
||||
// Filter by type
|
||||
const marks = performance.getEntriesByType("mark");
|
||||
const measures = performance.getEntriesByType("measure");
|
||||
|
||||
// Retrieve by name
|
||||
const debugMarks = performance.getEntriesByName("debug-mark", "mark");
|
||||
```
|
||||
|
||||
### Removing Markers and Measures
|
||||
|
||||
```javascript
|
||||
// Clear all marks
|
||||
performance.clearMarks();
|
||||
|
||||
// Remove specific mark
|
||||
performance.clearMarks("myMarker");
|
||||
|
||||
// Clear all measures
|
||||
performance.clearMeasures();
|
||||
|
||||
// Remove specific measure
|
||||
performance.clearMeasures("myMeasure");
|
||||
```
|
||||
|
||||
### Advantages Over Date.now() and performance.now()
|
||||
|
||||
- Meaningful names for better organization
|
||||
- Integrates with browser developer tools (Performance Panels)
|
||||
- Works seamlessly with other Performance APIs like `PerformanceObserver`
|
||||
- Better tooling integration overall
|
||||
366
skills/create-web-form/references/xml.md
Normal file
366
skills/create-web-form/references/xml.md
Normal file
@@ -0,0 +1,366 @@
|
||||
# XML Reference
|
||||
|
||||
---
|
||||
|
||||
## XML Introduction
|
||||
|
||||
> Source: <https://developer.mozilla.org/en-US/docs/Web/XML/Guides/XML_introduction>
|
||||
|
||||
### Overview
|
||||
|
||||
**XML (Extensible Markup Language)** is a markup language similar to HTML, but without predefined tags. Instead, you define your own tags designed for your specific needs. It enables powerful data storage in a standardized format that can be stored, searched, and shared across systems and platforms.
|
||||
|
||||
**XML-based languages include:** XHTML, MathML, SVG, RSS, and RDF.
|
||||
|
||||
### Structure of an XML Document
|
||||
|
||||
#### XML Declaration
|
||||
|
||||
An XML declaration transmits metadata about the document.
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
```
|
||||
|
||||
**Attributes:**
|
||||
|
||||
- **`version`** -- The XML version used in the document.
|
||||
- **`encoding`** -- The character encoding used in the document.
|
||||
|
||||
#### Comments
|
||||
|
||||
```xml
|
||||
<!-- Comment -->
|
||||
```
|
||||
|
||||
### "Correct" XML (Valid and Well-Formed)
|
||||
|
||||
For an XML document to be correct, it must fulfill these conditions:
|
||||
|
||||
1. Document must be **well-formed**.
|
||||
2. Document must conform to **all XML syntax rules**.
|
||||
3. Document must conform to **semantic rules** (usually set in an XML schema or DTD).
|
||||
|
||||
#### Example -- Incorrect XML
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<message>
|
||||
<warning>
|
||||
Hello World
|
||||
<!--missing </warning> -->
|
||||
</message>
|
||||
```
|
||||
|
||||
#### Example -- Corrected XML
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<message>
|
||||
<warning>
|
||||
Hello World
|
||||
</warning>
|
||||
</message>
|
||||
```
|
||||
|
||||
A document containing undefined tags is invalid. Tags must be properly defined in a schema or DTD.
|
||||
|
||||
### Character References
|
||||
|
||||
Like HTML, XML uses character references for special reserved characters:
|
||||
|
||||
| Entity | Character | Description |
|
||||
|-----------|-----------|--------------------------|
|
||||
| `<` | `<` | Less than sign |
|
||||
| `>` | `>` | Greater than sign |
|
||||
| `&` | `&` | Ampersand |
|
||||
| `"` | `"` | Double quotation mark |
|
||||
| `'` | `'` | Apostrophe / single quote |
|
||||
|
||||
#### Custom Entity Definition
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE body [
|
||||
<!ENTITY warning "Warning: Something bad happened... please refresh and try again.">
|
||||
]>
|
||||
<body>
|
||||
<message> &warning; </message>
|
||||
</body>
|
||||
```
|
||||
|
||||
#### Numeric Character References
|
||||
|
||||
Use numeric references for special characters:
|
||||
|
||||
- `©` = (c) (copyright symbol)
|
||||
|
||||
### Displaying XML
|
||||
|
||||
#### Using a CSS Stylesheet
|
||||
|
||||
```xml
|
||||
<?xml-stylesheet type="text/css" href="stylesheet.css"?>
|
||||
```
|
||||
|
||||
#### Using XSLT (Recommended for Complex Transformations)
|
||||
|
||||
```xml
|
||||
<?xml-stylesheet type="text/xsl" href="transform.xsl"?>
|
||||
```
|
||||
|
||||
**XSLT (Extensible Stylesheet Language Transformations)** is a powerful method to transform XML into other languages such as HTML, making XML incredibly versatile.
|
||||
|
||||
### Key Takeaways
|
||||
|
||||
- XML is **standardized**, ensuring data can be parsed consistently across systems.
|
||||
- XML documents require proper **nesting and closing of tags** to be well-formed.
|
||||
- XML is **platform and language agnostic**.
|
||||
- Use **DTD or XML Schema** to define valid tag structures.
|
||||
- Use **XSLT** for powerful XML transformation capabilities.
|
||||
|
||||
---
|
||||
|
||||
## Parsing and Serializing XML
|
||||
|
||||
> Source: <https://developer.mozilla.org/en-US/docs/Web/XML/Guides/Parsing_and_serializing_XML>
|
||||
|
||||
### Overview
|
||||
|
||||
At times, you may need to parse XML content and convert it into a DOM tree, or conversely, serialize an existing DOM tree into XML.
|
||||
|
||||
### Key Web Platform Objects
|
||||
|
||||
| Object | Purpose |
|
||||
|----------------------|----------------------------------------------------------------------------------------------|
|
||||
| **XMLSerializer** | Serializes DOM trees, converting them into strings containing XML |
|
||||
| **DOMParser** | Constructs a DOM tree by parsing a string containing XML, returning an XMLDocument or Document |
|
||||
| **fetch()** | Loads content from a URL; XML content is returned as a text string you can parse with DOMParser |
|
||||
| **XMLHttpRequest** | Precursor to fetch(); can return a resource as a Document via its `responseXML` property |
|
||||
| **XPath** | Creates address strings for specific portions of an XML document |
|
||||
|
||||
### Creating an XML Document
|
||||
|
||||
#### Parsing Strings into DOM Trees
|
||||
|
||||
```javascript
|
||||
const xmlStr = '<q id="a"><span id="b">hey!</span></q>';
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(xmlStr, "application/xml");
|
||||
// print the name of the root element or error message
|
||||
const errorNode = doc.querySelector("parsererror");
|
||||
if (errorNode) {
|
||||
console.log("error while parsing");
|
||||
} else {
|
||||
console.log(doc.documentElement.nodeName);
|
||||
}
|
||||
```
|
||||
|
||||
#### Parsing URL-Addressable Resources into DOM Trees
|
||||
|
||||
Using `fetch()`:
|
||||
|
||||
```javascript
|
||||
fetch("example.xml")
|
||||
.then((response) => response.text())
|
||||
.then((text) => {
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(text, "text/xml");
|
||||
console.log(doc.documentElement.nodeName);
|
||||
});
|
||||
```
|
||||
|
||||
This fetches the resource as a text string, then uses `DOMParser.parseFromString()` to construct an `XMLDocument`.
|
||||
|
||||
**Note:** If the document is HTML, the code returns a `Document`. If the document is XML, the resulting object is an `XMLDocument`. The two types are essentially the same; the difference is largely historical.
|
||||
|
||||
### Serializing an XML Document
|
||||
|
||||
#### Serializing DOM Trees to Strings
|
||||
|
||||
To serialize a DOM tree `doc` into XML text, call `XMLSerializer.serializeToString()`:
|
||||
|
||||
```javascript
|
||||
const serializer = new XMLSerializer();
|
||||
const xmlStr = serializer.serializeToString(doc);
|
||||
```
|
||||
|
||||
#### Serializing HTML Documents
|
||||
|
||||
If the DOM is an HTML document, you can use:
|
||||
|
||||
Using `innerHTML` (descendants only):
|
||||
|
||||
```javascript
|
||||
const docInnerHtml = document.documentElement.innerHTML;
|
||||
```
|
||||
|
||||
Using `outerHTML` (node and all descendants):
|
||||
|
||||
```javascript
|
||||
const docOuterHtml = document.documentElement.outerHTML;
|
||||
```
|
||||
|
||||
### Related Technologies
|
||||
|
||||
- XPath
|
||||
- fetch()
|
||||
- XMLHttpRequest
|
||||
- Document, XMLDocument, and HTMLDocument APIs
|
||||
|
||||
---
|
||||
|
||||
## OpenSearch Description Format
|
||||
|
||||
> Source: <https://developer.mozilla.org/en-US/docs/Web/XML/Guides/OpenSearch>
|
||||
|
||||
### Overview
|
||||
|
||||
The **OpenSearch description format** allows websites to describe their search engine interface, enabling browsers and client applications to integrate site-specific search functionality into the address bar. Supported by Firefox, Edge, Safari, and Chrome.
|
||||
|
||||
- Browsers query search engines via URL templates.
|
||||
- The browser fills in the user's search terms at specified placeholders.
|
||||
- Example: `https://example.com/search?q={searchTerms}` becomes `https://example.com/search?q=foo`.
|
||||
- Sites register search engines via an XML description file linked in HTML.
|
||||
- **Note:** Chrome registers site search engines as "inactive" by default; users must manually activate them.
|
||||
|
||||
### OpenSearch Description File
|
||||
|
||||
#### Basic XML Template
|
||||
|
||||
```xml
|
||||
<OpenSearchDescription
|
||||
xmlns="http://a9.com/-/spec/opensearch/1.1/"
|
||||
xmlns:moz="http://www.mozilla.org/2006/browser/search/">
|
||||
<ShortName>[SNK]</ShortName>
|
||||
<Description>[Search engine full name and summary]</Description>
|
||||
<InputEncoding>[UTF-8]</InputEncoding>
|
||||
<Image width="16" height="16" type="image/x-icon">[https://example.com/favicon.ico]</Image>
|
||||
<Url type="text/html" template="[searchURL]"/>
|
||||
<Url type="application/x-suggestions+json" template="[suggestionURL]"/>
|
||||
</OpenSearchDescription>
|
||||
```
|
||||
|
||||
### Element Specifications
|
||||
|
||||
#### ShortName
|
||||
|
||||
- Short name for the search engine.
|
||||
- **Must be 16 or fewer characters.**
|
||||
- Plain text only; no HTML or markup.
|
||||
|
||||
#### Description
|
||||
|
||||
- Brief description of the search engine.
|
||||
- **Maximum 1024 characters.**
|
||||
- Plain text only; no HTML or markup.
|
||||
|
||||
#### InputEncoding
|
||||
|
||||
- Character encoding for submitting input to the search engine.
|
||||
- Example: `UTF-8`.
|
||||
|
||||
#### Image
|
||||
|
||||
- URL or data URL for the search engine icon.
|
||||
- **Recommended sizes:**
|
||||
- 16x16 image of type `image/x-icon` (e.g., `/favicon.ico`)
|
||||
- 64x64 image of type `image/jpeg` or `image/png`
|
||||
|
||||
**Icon URL examples:**
|
||||
|
||||
```xml
|
||||
<Image height="16" width="16" type="image/x-icon">https://example.com/favicon.ico</Image>
|
||||
```
|
||||
|
||||
```xml
|
||||
<Image height="16" width="16">data:image/x-icon;base64,AAABAAEAEBAAA...DAAA=</Image>
|
||||
```
|
||||
|
||||
**Important icon notes:**
|
||||
|
||||
- Firefox caches icons as base64 `data:` URLs.
|
||||
- Search plug-ins are stored in the profile's `searchplugins/` folder.
|
||||
- `http:` and `https:` URLs are converted to `data:` URLs.
|
||||
- **Firefox rejects remotely-loaded icons larger than 10 kilobytes.**
|
||||
|
||||
#### Url
|
||||
|
||||
Describes the URL(s) to use for search queries using the `template` attribute.
|
||||
|
||||
**Firefox-supported URL types:**
|
||||
|
||||
| Type | Purpose |
|
||||
|-------------------------------------------|--------------------------------------------|
|
||||
| `type="text/html"` | Actual search query URL |
|
||||
| `type="application/x-suggestions+json"` | Search suggestions in JSON format |
|
||||
| `type="application/x-moz-keywordsearch"` | Keyword search in location bar (Firefox-only) |
|
||||
|
||||
**Dynamic parameters:**
|
||||
|
||||
- `{searchTerms}` -- The user's search terms.
|
||||
- Other OpenSearch 1.1 parameters are also supported.
|
||||
|
||||
### Linking to an OpenSearch Description File
|
||||
|
||||
#### HTML Link Element
|
||||
|
||||
```html
|
||||
<link
|
||||
rel="search"
|
||||
type="application/opensearchdescription+xml"
|
||||
title="[searchTitle]"
|
||||
href="[descriptionURL]" />
|
||||
```
|
||||
|
||||
**Required attributes:**
|
||||
|
||||
- `rel="search"` -- Establishes search engine relationship.
|
||||
- `type="application/opensearchdescription+xml"` -- MIME type.
|
||||
- `title="[searchTitle]"` -- Name of search (must match `<ShortName>`).
|
||||
- `href="[descriptionURL]"` -- URL to the XML description file.
|
||||
|
||||
#### Multiple Search Engines Example
|
||||
|
||||
```html
|
||||
<link
|
||||
rel="search"
|
||||
type="application/opensearchdescription+xml"
|
||||
title="MySite: By Author"
|
||||
href="http://example.com/mysiteauthor.xml" />
|
||||
|
||||
<link
|
||||
rel="search"
|
||||
type="application/opensearchdescription+xml"
|
||||
title="MySite: By Title"
|
||||
href="http://example.com/mysitetitle.xml" />
|
||||
```
|
||||
|
||||
### Supporting Automatic Updates
|
||||
|
||||
Include an extra `Url` element with automatic update capability:
|
||||
|
||||
```xml
|
||||
<Url
|
||||
type="application/opensearchdescription+xml"
|
||||
rel="self"
|
||||
template="https://example.com/mysearchdescription.xml" />
|
||||
```
|
||||
|
||||
This allows the OpenSearch description file to update automatically.
|
||||
|
||||
### Troubleshooting Tips
|
||||
|
||||
1. **Server Content-Type** -- Serve OpenSearch descriptions with `Content-Type: application/opensearchdescription+xml`.
|
||||
2. **XML Well-Formedness** -- Load the file directly in a browser to validate. Ampersands (`&`) must be escaped as `&`. Tags must be closed with a trailing slash or matching end tag.
|
||||
3. **Missing xmlns Attribute** -- Always include `xmlns="http://a9.com/-/spec/opensearch/1.1/"` or Firefox will report: "Firefox could not download the search plugin."
|
||||
4. **Missing text/html URL** -- A `text/html` URL type **must** be included; Atom or RSS-only URLs will generate an error.
|
||||
5. **Favicon Size** -- Remotely fetched favicons must not exceed 10KB.
|
||||
6. **Browser Activation** -- Browsers may not activate site search shortcuts by default; check browser settings and manually activate if needed.
|
||||
|
||||
#### Firefox Debugging
|
||||
|
||||
Use `about:config` to enable logging:
|
||||
|
||||
1. Set preference `browser.search.log` to `true`.
|
||||
2. View logs in Firefox Browser Console: Tools > Browser Tools > Browser Console.
|
||||
Reference in New Issue
Block a user