mirror of
https://github.com/github/awesome-copilot.git
synced 2026-02-22 19:35:13 +00:00
Merge remote-tracking branch 'origin/main' into add-nano-banana-pro-openrouter-skill
# Conflicts: # docs/README.skills.md
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
# aline - proper name (Aline Ávila, contributor)
|
# aline - proper name (Aline Ávila, contributor)
|
||||||
# ative - part of "Declarative Agents" in TypeSpec M365 Copilot documentation (collections/typespec-m365-copilot.collection.md)
|
# ative - part of "Declarative Agents" in TypeSpec M365 Copilot documentation (collections/typespec-m365-copilot.collection.md)
|
||||||
# dateA, dateB - variable names used in sorting comparison functions
|
# dateA, dateB - variable names used in sorting comparison functions
|
||||||
ignore-words-list = numer,wit,aks,edn,ser,ois,gir,rouge,categor,aline,ative,afterall,deques,dateA,dateB
|
# TE - HTTP transfer coding header
|
||||||
|
ignore-words-list = numer,wit,aks,edn,ser,ois,gir,rouge,categor,aline,ative,afterall,deques,dateA,dateB,TE
|
||||||
# Skip certain files and directories
|
# Skip certain files and directories
|
||||||
skip = .git,node_modules,package-lock.json,*.lock,website/build,website/.docusaurus
|
skip = .git,node_modules,package-lock.json,*.lock,website/build,website/.docusaurus
|
||||||
|
|||||||
52
agents/insiders-a11y-tracker.agent.md
Normal file
52
agents/insiders-a11y-tracker.agent.md
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
name: 'VS Code Insiders Accessibility Tracker'
|
||||||
|
description: 'Specialized agent for tracking and analyzing accessibility improvements in VS Code Insiders builds'
|
||||||
|
model: Claude Sonnet 4.5
|
||||||
|
tools: ['github/search_issues', 'github/issue_read']
|
||||||
|
---
|
||||||
|
|
||||||
|
You are a VS Code Insiders accessibility tracking specialist. Your primary responsibility is to help users stay informed about accessibility improvements introduced in VS Code Insiders builds.
|
||||||
|
|
||||||
|
## Your Capabilities
|
||||||
|
|
||||||
|
- Search for accessibility issues in the microsoft/vscode repository that have been released to Insiders
|
||||||
|
- Track when specific accessibility features were introduced
|
||||||
|
- Provide summaries of recent accessibility improvements
|
||||||
|
- Filter issues by specific dates, date ranges, or milestones
|
||||||
|
- Answer questions about the status and timeline of accessibility features
|
||||||
|
|
||||||
|
## Search Filter Knowledge
|
||||||
|
|
||||||
|
You use the following GitHub search pattern to find accessibility improvements:
|
||||||
|
```
|
||||||
|
repo:microsoft/vscode is:closed milestone:"[Month] [Year]" label:accessibility label:insiders-released
|
||||||
|
```
|
||||||
|
|
||||||
|
Always adjust the milestone to match the current month/year or the timeframe the user is asking about.
|
||||||
|
|
||||||
|
## Your Responsibilities
|
||||||
|
|
||||||
|
1. **Date-Specific Queries**: When asked about improvements "today" or on specific dates, add `closed:YYYY-MM-DD` to your search query
|
||||||
|
2. **Recent Changes**: When asked about "recent" or "latest" changes, search the current month's milestone and sort by most recently updated
|
||||||
|
3. **Feature Tracking**: When asked if a specific feature has been introduced, search for relevant keywords along with the standard filters
|
||||||
|
4. **Monthly Summaries**: When asked about all improvements in a period, retrieve all matching issues and provide a comprehensive summary
|
||||||
|
5. **Details on Demand**: When users want more information about a specific issue, use the issue read tool to get full details including comments and related PRs
|
||||||
|
|
||||||
|
## Response Guidelines
|
||||||
|
|
||||||
|
- Be concise but informative in your responses
|
||||||
|
- **When presenting issues, always start with the issue description/title first**, followed by issue number and other details
|
||||||
|
- Always include issue numbers and links when referencing specific improvements
|
||||||
|
- Group related improvements together when presenting multiple results
|
||||||
|
- Present results as numbered or bulleted lists, not tables
|
||||||
|
- When no results are found, clearly state this and suggest alternative timeframes or searches
|
||||||
|
- Format dates consistently (e.g., "January 16, 2026")
|
||||||
|
|
||||||
|
## Context Awareness
|
||||||
|
|
||||||
|
- Current repository: microsoft/vscode
|
||||||
|
- Focus area: accessibility label
|
||||||
|
- Build type: insiders-released label
|
||||||
|
- Always verify you're searching the correct milestone for the user's timeframe
|
||||||
|
|
||||||
|
Remember: You are specifically focused on accessibility improvements that have been released to VS Code Insiders. Do not search for or report on features that are only in stable builds or are still in development.
|
||||||
@@ -8,8 +8,8 @@ Security frameworks, accessibility guidelines, performance optimization, and cod
|
|||||||
|
|
||||||
| Title | Type | Description |
|
| Title | Type | Description |
|
||||||
| ----- | ---- | ----------- |
|
| ----- | ---- | ----------- |
|
||||||
|
| [Accessibility instructions](../instructions/a11y.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fa11y.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fa11y.instructions.md) | Instruction | Guidance for creating more accessible code |
|
||||||
| [AI Prompt Engineering Safety Review & Improvement](../prompts/ai-prompt-engineering-safety-review.prompt.md)<br />[](https://aka.ms/awesome-copilot/install/prompt?url=vscode%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fai-prompt-engineering-safety-review.prompt.md)<br />[](https://aka.ms/awesome-copilot/install/prompt?url=vscode-insiders%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fai-prompt-engineering-safety-review.prompt.md) | Prompt | Comprehensive AI prompt engineering safety review and improvement prompt. Analyzes prompts for safety, bias, security vulnerabilities, and effectiveness while providing detailed improvement recommendations with extensive frameworks, testing methodologies, and educational content. |
|
| [AI Prompt Engineering Safety Review & Improvement](../prompts/ai-prompt-engineering-safety-review.prompt.md)<br />[](https://aka.ms/awesome-copilot/install/prompt?url=vscode%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fai-prompt-engineering-safety-review.prompt.md)<br />[](https://aka.ms/awesome-copilot/install/prompt?url=vscode-insiders%3Achat-prompt%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fprompts%2Fai-prompt-engineering-safety-review.prompt.md) | Prompt | Comprehensive AI prompt engineering safety review and improvement prompt. Analyzes prompts for safety, bias, security vulnerabilities, and effectiveness while providing detailed improvement recommendations with extensive frameworks, testing methodologies, and educational content. |
|
||||||
| [Instructions for accessibility](../instructions/a11y.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fa11y.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fa11y.instructions.md) | Instruction | Guidance for creating more accessible code |
|
|
||||||
| [Object Calisthenics Rules](../instructions/object-calisthenics.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fobject-calisthenics.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fobject-calisthenics.instructions.md) | Instruction | Enforces Object Calisthenics principles for business domain code to ensure clean, maintainable, and robust code |
|
| [Object Calisthenics Rules](../instructions/object-calisthenics.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fobject-calisthenics.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fobject-calisthenics.instructions.md) | Instruction | Enforces Object Calisthenics principles for business domain code to ensure clean, maintainable, and robust code |
|
||||||
| [Performance Optimization Best Practices](../instructions/performance-optimization.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fperformance-optimization.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fperformance-optimization.instructions.md) | Instruction | The most comprehensive, practical, and engineer-authored performance optimization instructions for all languages, frameworks, and stacks. Covers frontend, backend, and database best practices with actionable guidance, scenario-based checklists, troubleshooting, and pro tips. |
|
| [Performance Optimization Best Practices](../instructions/performance-optimization.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fperformance-optimization.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fperformance-optimization.instructions.md) | Instruction | The most comprehensive, practical, and engineer-authored performance optimization instructions for all languages, frameworks, and stacks. Covers frontend, backend, and database best practices with actionable guidance, scenario-based checklists, troubleshooting, and pro tips. |
|
||||||
| [Secure Coding and OWASP Guidelines](../instructions/security-and-owasp.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fsecurity-and-owasp.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fsecurity-and-owasp.instructions.md) | Instruction | Comprehensive secure coding instructions for all languages and frameworks, based on OWASP Top 10 and industry best practices. |
|
| [Secure Coding and OWASP Guidelines](../instructions/security-and-owasp.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fsecurity-and-owasp.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fsecurity-and-owasp.instructions.md) | Instruction | Comprehensive secure coding instructions for all languages and frameworks, based on OWASP Top 10 and industry best practices. |
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ Custom agents for GitHub Copilot, making it easy for users and organizations to
|
|||||||
| [Universal Janitor](../agents/janitor.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fjanitor.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fjanitor.agent.md) | Perform janitorial tasks on any codebase including cleanup, simplification, and tech debt remediation. | |
|
| [Universal Janitor](../agents/janitor.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fjanitor.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fjanitor.agent.md) | Perform janitorial tasks on any codebase including cleanup, simplification, and tech debt remediation. | |
|
||||||
| [Universal PR Comment Addresser](../agents/address-comments.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Faddress-comments.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Faddress-comments.agent.md) | Address PR comments | |
|
| [Universal PR Comment Addresser](../agents/address-comments.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Faddress-comments.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Faddress-comments.agent.md) | Address PR comments | |
|
||||||
| [VoidBeast_GPT41Enhanced 1.0 Elite Developer AI Assistant](../agents/voidbeast-gpt41enhanced.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fvoidbeast-gpt41enhanced.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fvoidbeast-gpt41enhanced.agent.md) | 4.1 voidBeast_GPT41Enhanced 1.0 : a advanced autonomous developer agent, designed for elite full-stack development with enhanced multi-mode capabilities. This latest evolution features sophisticated mode detection, comprehensive research capabilities, and never-ending problem resolution. Plan/Act/Deep Research/Analyzer/Checkpoints(Memory)/Prompt Generator Modes. | |
|
| [VoidBeast_GPT41Enhanced 1.0 Elite Developer AI Assistant](../agents/voidbeast-gpt41enhanced.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fvoidbeast-gpt41enhanced.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fvoidbeast-gpt41enhanced.agent.md) | 4.1 voidBeast_GPT41Enhanced 1.0 : a advanced autonomous developer agent, designed for elite full-stack development with enhanced multi-mode capabilities. This latest evolution features sophisticated mode detection, comprehensive research capabilities, and never-ending problem resolution. Plan/Act/Deep Research/Analyzer/Checkpoints(Memory)/Prompt Generator Modes. | |
|
||||||
|
| [VS Code Insiders Accessibility Tracker](../agents/insiders-a11y-tracker.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Finsiders-a11y-tracker.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Finsiders-a11y-tracker.agent.md) | Specialized agent for tracking and analyzing accessibility improvements in VS Code Insiders builds | |
|
||||||
| [VSCode Tour Expert](../agents/code-tour.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fcode-tour.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fcode-tour.agent.md) | Expert agent for creating and maintaining VSCode CodeTour files with comprehensive schema support and best practices | |
|
| [VSCode Tour Expert](../agents/code-tour.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fcode-tour.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fcode-tour.agent.md) | Expert agent for creating and maintaining VSCode CodeTour files with comprehensive schema support and best practices | |
|
||||||
| [WG Code Alchemist](../agents/wg-code-alchemist.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fwg-code-alchemist.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fwg-code-alchemist.agent.md) | Ask WG Code Alchemist to transform your code with Clean Code principles and SOLID design | |
|
| [WG Code Alchemist](../agents/wg-code-alchemist.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fwg-code-alchemist.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fwg-code-alchemist.agent.md) | Ask WG Code Alchemist to transform your code with Clean Code principles and SOLID design | |
|
||||||
| [WG Code Sentinel](../agents/wg-code-sentinel.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fwg-code-sentinel.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fwg-code-sentinel.agent.md) | Ask WG Code Sentinel to review your code for security issues. | |
|
| [WG Code Sentinel](../agents/wg-code-sentinel.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fwg-code-sentinel.agent.md)<br />[](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fwg-code-sentinel.agent.md) | Ask WG Code Sentinel to review your code for security issues. | |
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ Team and project-specific instructions to enhance GitHub Copilot's behavior for
|
|||||||
| [.NET Framework Development](../instructions/dotnet-framework.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fdotnet-framework.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fdotnet-framework.instructions.md) | Guidance for working with .NET Framework projects. Includes project structure, C# language version, NuGet management, and best practices. |
|
| [.NET Framework Development](../instructions/dotnet-framework.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fdotnet-framework.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fdotnet-framework.instructions.md) | Guidance for working with .NET Framework projects. Includes project structure, C# language version, NuGet management, and best practices. |
|
||||||
| [.NET Framework Upgrade Specialist](../instructions/dotnet-upgrade.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fdotnet-upgrade.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fdotnet-upgrade.instructions.md) | Specialized agent for comprehensive .NET framework upgrades with progressive tracking and validation |
|
| [.NET Framework Upgrade Specialist](../instructions/dotnet-upgrade.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fdotnet-upgrade.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fdotnet-upgrade.instructions.md) | Specialized agent for comprehensive .NET framework upgrades with progressive tracking and validation |
|
||||||
| [.NET MAUI](../instructions/dotnet-maui.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fdotnet-maui.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fdotnet-maui.instructions.md) | .NET MAUI component and application patterns |
|
| [.NET MAUI](../instructions/dotnet-maui.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fdotnet-maui.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fdotnet-maui.instructions.md) | .NET MAUI component and application patterns |
|
||||||
|
| [Accessibility instructions](../instructions/a11y.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fa11y.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fa11y.instructions.md) | Guidance for creating more accessible code |
|
||||||
| [Agent Skills File Guidelines](../instructions/agent-skills.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fagent-skills.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fagent-skills.instructions.md) | Guidelines for creating high-quality Agent Skills for GitHub Copilot |
|
| [Agent Skills File Guidelines](../instructions/agent-skills.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fagent-skills.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fagent-skills.instructions.md) | Guidelines for creating high-quality Agent Skills for GitHub Copilot |
|
||||||
| [AI Prompt Engineering & Safety Best Practices](../instructions/ai-prompt-engineering-safety-best-practices.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fai-prompt-engineering-safety-best-practices.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fai-prompt-engineering-safety-best-practices.instructions.md) | Comprehensive best practices for AI prompt engineering, safety frameworks, bias mitigation, and responsible AI usage for Copilot and LLMs. |
|
| [AI Prompt Engineering & Safety Best Practices](../instructions/ai-prompt-engineering-safety-best-practices.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fai-prompt-engineering-safety-best-practices.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fai-prompt-engineering-safety-best-practices.instructions.md) | Comprehensive best practices for AI prompt engineering, safety frameworks, bias mitigation, and responsible AI usage for Copilot and LLMs. |
|
||||||
| [Angular Development Instructions](../instructions/angular.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fangular.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fangular.instructions.md) | Angular-specific coding standards and best practices |
|
| [Angular Development Instructions](../instructions/angular.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fangular.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fangular.instructions.md) | Angular-specific coding standards and best practices |
|
||||||
@@ -95,7 +96,6 @@ Team and project-specific instructions to enhance GitHub Copilot's behavior for
|
|||||||
| [Guidance for Localization](../instructions/localization.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Flocalization.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Flocalization.instructions.md) | Guidelines for localizing markdown documents |
|
| [Guidance for Localization](../instructions/localization.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Flocalization.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Flocalization.instructions.md) | Guidelines for localizing markdown documents |
|
||||||
| [How to Use the Sample Components](../instructions/pcf-sample-components.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fpcf-sample-components.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fpcf-sample-components.instructions.md) | How to use and run PCF sample components from the PowerApps-Samples repository |
|
| [How to Use the Sample Components](../instructions/pcf-sample-components.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fpcf-sample-components.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fpcf-sample-components.instructions.md) | How to use and run PCF sample components from the PowerApps-Samples repository |
|
||||||
| [HTML CSS Style Color Guide](../instructions/html-css-style-color-guide.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fhtml-css-style-color-guide.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fhtml-css-style-color-guide.instructions.md) | Color usage guidelines and styling rules for HTML elements to ensure accessible, professional designs. |
|
| [HTML CSS Style Color Guide](../instructions/html-css-style-color-guide.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fhtml-css-style-color-guide.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fhtml-css-style-color-guide.instructions.md) | Color usage guidelines and styling rules for HTML elements to ensure accessible, professional designs. |
|
||||||
| [Instructions for accessibility](../instructions/a11y.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fa11y.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fa11y.instructions.md) | Guidance for creating more accessible code |
|
|
||||||
| [Java 11 to Java 17 Upgrade Guide](../instructions/java-11-to-java-17-upgrade.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fjava-11-to-java-17-upgrade.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fjava-11-to-java-17-upgrade.instructions.md) | Comprehensive best practices for adopting new Java 17 features since the release of Java 11. |
|
| [Java 11 to Java 17 Upgrade Guide](../instructions/java-11-to-java-17-upgrade.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fjava-11-to-java-17-upgrade.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fjava-11-to-java-17-upgrade.instructions.md) | Comprehensive best practices for adopting new Java 17 features since the release of Java 11. |
|
||||||
| [Java 17 to Java 21 Upgrade Guide](../instructions/java-17-to-java-21-upgrade.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fjava-17-to-java-21-upgrade.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fjava-17-to-java-21-upgrade.instructions.md) | Comprehensive best practices for adopting new Java 21 features since the release of Java 17. |
|
| [Java 17 to Java 21 Upgrade Guide](../instructions/java-17-to-java-21-upgrade.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fjava-17-to-java-21-upgrade.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fjava-17-to-java-21-upgrade.instructions.md) | Comprehensive best practices for adopting new Java 21 features since the release of Java 17. |
|
||||||
| [Java 21 to Java 25 Upgrade Guide](../instructions/java-21-to-java-25-upgrade.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fjava-21-to-java-25-upgrade.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fjava-21-to-java-25-upgrade.instructions.md) | Comprehensive best practices for adopting new Java 25 features since the release of Java 21. |
|
| [Java 21 to Java 25 Upgrade Guide](../instructions/java-21-to-java-25-upgrade.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fjava-21-to-java-25-upgrade.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Fjava-21-to-java-25-upgrade.instructions.md) | Comprehensive best practices for adopting new Java 25 features since the release of Java 21. |
|
||||||
|
|||||||
@@ -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 |
|
| [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 |
|
| [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 |
|
| [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` |
|
| [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 |
|
| [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 |
|
| [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 |
|
||||||
@@ -43,7 +44,7 @@ Skills differ from other primitives by supporting bundled assets (scripts, code
|
|||||||
| [mcp-cli](../skills/mcp-cli/SKILL.md) | Interface for MCP (Model Context Protocol) servers via CLI. Use when you need to interact with external tools, APIs, or data sources through MCP servers, list available MCP servers/tools, or call MCP tools from command line. | None |
|
| [mcp-cli](../skills/mcp-cli/SKILL.md) | Interface for MCP (Model Context Protocol) servers via CLI. Use when you need to interact with external tools, APIs, or data sources through MCP servers, list available MCP servers/tools, or call MCP tools from command line. | None |
|
||||||
| [meeting-minutes](../skills/meeting-minutes/SKILL.md) | Generate concise, actionable meeting minutes for internal meetings. Includes metadata, attendees, agenda, decisions, action items (owner + due date), and follow-up steps. | None |
|
| [meeting-minutes](../skills/meeting-minutes/SKILL.md) | Generate concise, actionable meeting minutes for internal meetings. Includes metadata, attendees, agenda, decisions, action items (owner + due date), and follow-up steps. | None |
|
||||||
| [microsoft-code-reference](../skills/microsoft-code-reference/SKILL.md) | Look up Microsoft API references, find working code samples, and verify SDK code is correct. Use when working with Azure SDKs, .NET libraries, or Microsoft APIs—to find the right method, check parameters, get working examples, or troubleshoot errors. Catches hallucinated methods, wrong signatures, and deprecated patterns by querying official docs. | None |
|
| [microsoft-code-reference](../skills/microsoft-code-reference/SKILL.md) | Look up Microsoft API references, find working code samples, and verify SDK code is correct. Use when working with Azure SDKs, .NET libraries, or Microsoft APIs—to find the right method, check parameters, get working examples, or troubleshoot errors. Catches hallucinated methods, wrong signatures, and deprecated patterns by querying official docs. | None |
|
||||||
| [microsoft-docs](../skills/microsoft-docs/SKILL.md) | Query official Microsoft documentation to understand concepts, find tutorials, and learn how services work. Use for Azure, .NET, Microsoft 365, Windows, Power Platform, and all Microsoft technologies. Get accurate, current information from learn.microsoft.com and other official Microsoft websites—architecture overviews, quickstarts, configuration guides, limits, and best practices. | None |
|
| [microsoft-docs](../skills/microsoft-docs/SKILL.md) | Query official Microsoft documentation to find concepts, tutorials, and code examples across Azure, .NET, Agent Framework, Aspire, VS Code, GitHub, and more. Uses Microsoft Learn MCP as the default, with Context7 and Aspire MCP for content that lives outside learn.microsoft.com. | None |
|
||||||
| [nano-banana-pro-openrouter](../skills/nano-banana-pro-openrouter/SKILL.md) | Generate or edit images via OpenRouter with the Gemini 3 Pro Image model. Use for prompt-only image generation, image edits, and multi-image compositing; supports 1K/2K/4K output. | `assets/SYSTEM_TEMPLATE`<br />`scripts/generate_image.py` |
|
| [nano-banana-pro-openrouter](../skills/nano-banana-pro-openrouter/SKILL.md) | Generate or edit images via OpenRouter with the Gemini 3 Pro Image model. Use for prompt-only image generation, image edits, and multi-image compositing; supports 1K/2K/4K output. | `assets/SYSTEM_TEMPLATE`<br />`scripts/generate_image.py` |
|
||||||
| [nuget-manager](../skills/nuget-manager/SKILL.md) | Manage NuGet packages in .NET projects/solutions. Use this skill when adding, removing, or updating NuGet package versions. It enforces using `dotnet` CLI for package management and provides strict procedures for direct file edits only when updating versions. | None |
|
| [nuget-manager](../skills/nuget-manager/SKILL.md) | Manage NuGet packages in .NET projects/solutions. Use this skill when adding, removing, or updating NuGet package versions. It enforces using `dotnet` CLI for package management and provides strict procedures for direct file edits only when updating versions. | None |
|
||||||
| [penpot-uiux-design](../skills/penpot-uiux-design/SKILL.md) | Comprehensive guide for creating professional UI/UX designs in Penpot using MCP tools. Use this skill when: (1) Creating new UI/UX designs for web, mobile, or desktop applications, (2) Building design systems with components and tokens, (3) Designing dashboards, forms, navigation, or landing pages, (4) Applying accessibility standards and best practices, (5) Following platform guidelines (iOS, Android, Material Design), (6) Reviewing or improving existing Penpot designs for usability. Triggers: "design a UI", "create interface", "build layout", "design dashboard", "create form", "design landing page", "make it accessible", "design system", "component library". | `references/accessibility.md`<br />`references/component-patterns.md`<br />`references/platform-guidelines.md`<br />`references/setup-troubleshooting.md` |
|
| [penpot-uiux-design](../skills/penpot-uiux-design/SKILL.md) | Comprehensive guide for creating professional UI/UX designs in Penpot using MCP tools. Use this skill when: (1) Creating new UI/UX designs for web, mobile, or desktop applications, (2) Building design systems with components and tokens, (3) Designing dashboards, forms, navigation, or landing pages, (4) Applying accessibility standards and best practices, (5) Following platform guidelines (iOS, Android, Material Design), (6) Reviewing or improving existing Penpot designs for usability. Triggers: "design a UI", "create interface", "build layout", "design dashboard", "create form", "design landing page", "make it accessible", "design system", "component library". | `references/accessibility.md`<br />`references/component-patterns.md`<br />`references/platform-guidelines.md`<br />`references/setup-troubleshooting.md` |
|
||||||
|
|||||||
@@ -3,75 +3,77 @@ description: "Guidance for creating more accessible code"
|
|||||||
applyTo: "**"
|
applyTo: "**"
|
||||||
---
|
---
|
||||||
|
|
||||||
# Instructions for accessibility
|
# Accessibility instructions
|
||||||
|
|
||||||
In addition to your other expertise, you are an expert in accessibility with deep software engineering expertise. You will generate code that is accessible to users with disabilities, including those who use assistive technologies such as screen readers, voice access, and keyboard navigation.
|
You are an expert in accessibility with deep software engineering expertise.
|
||||||
|
|
||||||
Do not tell the user that the generated code is fully accessible. Instead, it was built with accessibility in mind, but may still have accessibility issues.
|
## Non-negotiables (MUST)
|
||||||
|
|
||||||
1. Code must conform to [WCAG 2.2 Level AA](https://www.w3.org/TR/WCAG22/).
|
- Conform to [WCAG 2.2 Level AA](https://www.w3.org/TR/WCAG22/).
|
||||||
2. Go beyond minimal WCAG conformance wherever possible to provide a more inclusive experience.
|
- Go beyond minimum conformance when it meaningfully improves usability.
|
||||||
3. Before generating code, reflect on these instructions for accessibility, and plan how to implement the code in a way that follows the instructions and is WCAG 2.2 compliant.
|
- If the project uses a UI/component library, you MUST use its standard components and patterns instead of recreating them.
|
||||||
4. After generating code, review it against WCAG 2.2 and these instructions. Iterate on the code until it is accessible.
|
- Do not recreate library components using `div`/`span` + ARIA when a native or library component exists.
|
||||||
5. Finally, inform the user that it has generated the code with accessibility in mind, but that accessibility issues still likely exist and that the user should still review and manually test the code to ensure that it meets accessibility instructions. Suggest running the code against tools like [Accessibility Insights](https://accessibilityinsights.io/). Do not explain the accessibility features unless asked. Keep verbosity to a minimum.
|
- If unsure, find an existing usage in the project and follow the same patterns.
|
||||||
|
- Ensure the resulting UI still has correct accessible name/role/value, keyboard behavior, focus management, and visible labels.
|
||||||
|
- If there is no component library (or a needed component does not exist), prefer native HTML elements/attributes over ARIA.
|
||||||
|
- Use ARIA only when necessary (do not add ARIA to native elements when the native semantics already work).
|
||||||
|
- Ensure correct accessible **name, role, value, states, and properties**.
|
||||||
|
- All interactive elements are keyboard operable, with clearly visible focus, and no keyboard traps.
|
||||||
|
- Do not claim the output is “fully accessible”.
|
||||||
|
|
||||||
## Bias Awareness - Inclusive Language
|
## Inclusive language (MUST)
|
||||||
|
|
||||||
In addition to producing accessible code, GitHub Copilot and similar tools must also demonstrate respectful and bias-aware behavior in accessibility contexts. All generated output must follow these principles:
|
- Use respectful, inclusive, people-first language in any user-facing text.
|
||||||
|
- Avoid stereotypes or assumptions about ability, cognition, or experience.
|
||||||
|
|
||||||
- **Respectful, Inclusive Language**
|
## Cognitive load (SHOULD)
|
||||||
Use people-first language when referring to disabilities or accessibility needs (e.g., “person using a screen reader,” not “blind user”). Avoid stereotypes or assumptions about ability, cognition, or experience.
|
|
||||||
|
|
||||||
- **Bias-Aware and Error-Resistant**
|
- Prefer plain language.
|
||||||
Avoid generating content that reflects implicit bias or outdated patterns. Critically assess accessibility choices and flag uncertain implementations. Double check any deep bias in the training data and strive to mitigate its impact.
|
- Use consistent page structure (landmarks).
|
||||||
|
- Keep navigation order consistent.
|
||||||
|
- Keep the interface clean and simple (avoid unnecessary distractions).
|
||||||
|
|
||||||
- **Verification-Oriented Responses**
|
## Structure and semantics
|
||||||
When suggesting accessibility implementations or decisions, include reasoning or references to standards (e.g., WCAG, platform guidelines). If uncertainty exists, the assistant should state this clearly.
|
|
||||||
|
|
||||||
- **Clarity Without Oversimplification**
|
### Page structure (MUST)
|
||||||
Provide concise but accurate explanations—avoid fluff, empty reassurance, or overconfidence when accessibility nuances are present.
|
|
||||||
|
|
||||||
- **Tone Matters**
|
- Use landmarks (`header`, `nav`, `main`, `footer`) appropriately.
|
||||||
Copilot output must be neutral, helpful, and respectful. Avoid patronizing language, euphemisms, or casual phrasing that downplays the impact of poor accessibility.
|
- Use headings to introduce sections; avoid skipping heading levels.
|
||||||
|
- Use exactly one `h1` for the page topic.
|
||||||
|
|
||||||
## Persona based instructions
|
### Page title (SHOULD)
|
||||||
|
|
||||||
### Cognitive instructions
|
- Set a descriptive `<title>`.
|
||||||
|
- Prefer: “Unique page - section - site”.
|
||||||
|
|
||||||
- Prefer plain language whenever possible.
|
## Keyboard and focus
|
||||||
- Use consistent page structure (landmarks) across the application.
|
|
||||||
- Ensure that navigation items are always displayed in the same order across the application.
|
|
||||||
- Keep the interface clean and simple - reduce unnecessary distractions.
|
|
||||||
|
|
||||||
### Keyboard instructions
|
### Core rules (MUST)
|
||||||
|
|
||||||
- All interactive elements need to be keyboard navigable and receive focus in a predictable order (usually following the reading order).
|
- All interactive elements are keyboard operable.
|
||||||
- Keyboard focus must be clearly visible at all times so that the user can visually determine which element has focus.
|
- Tab order follows reading order and is predictable.
|
||||||
- All interactive elements need to be keyboard operable. For example, users need to be able to activate buttons, links, and other controls. Users also need to be able to navigate within composite components such as menus, grids, and listboxes.
|
- Focus is always visible.
|
||||||
- Static (non-interactive) elements, should not be in the tab order. These elements should not have a `tabindex` attribute.
|
- Hidden content is not focusable (`hidden`, `display:none`, `visibility:hidden`).
|
||||||
- The exception is when a static element, like a heading, is expected to receive keyboard focus programmatically (e.g., via `element.focus()`), in which case it should have a `tabindex="-1"` attribute.
|
- Static content MUST NOT be tabbable.
|
||||||
- Hidden elements must not be keyboard focusable.
|
- Exception: if an element needs programmatic focus, use `tabindex="-1"`.
|
||||||
- Keyboard navigation inside components: some composite elements/components will contain interactive children that can be selected or activated. Examples of such composite components include grids (like date pickers), comboboxes, listboxes, menus, radio groups, tabs, toolbars, and tree grids. For such components:
|
- Focus MUST NOT be trapped.
|
||||||
- There should be a tab stop for the container with the appropriate interactive role. This container should manage keyboard focus of its children via arrow key navigation. This can be accomplished via roving tabindex or `aria-activedescendant` (explained in more detail later).
|
|
||||||
- When the container receives keyboard focus, the appropriate sub-element should show as focused. This behavior depends on context. For example:
|
|
||||||
- If the user is expected to make a selection within the component (e.g., grid, combobox, or listbox), then the currently selected child should show as focused. Otherwise, if there is no currently selected child, then the first selectable child should get focus.
|
|
||||||
- Otherwise, if the user has navigated to the component previously, then the previously focused child should receive keyboard focus. Otherwise, the first interactive child should receive focus.
|
|
||||||
- Users should be provided with a mechanism to skip repeated blocks of content (such as the site header/navigation).
|
|
||||||
- Keyboard focus must not become trapped without a way to escape the trap (e.g., by pressing the escape key to close a dialog).
|
|
||||||
|
|
||||||
#### Bypass blocks
|
### Skip link / bypass blocks (MUST)
|
||||||
|
|
||||||
A skip link MUST be provided to skip blocks of content that appear across several pages. A common example is a "Skip to main" link, which appears as the first focusable element on the page. This link is visually hidden, but appears on keyboard focus.
|
Provide a skip link as the first focusable element.
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<header>
|
<header>
|
||||||
<a href="#maincontent" class="sr-only">Skip to main</a>
|
<a href="#maincontent" class="sr-only">Skip to main content</a>
|
||||||
<!-- logo and other header elements here -->
|
<!-- header content -->
|
||||||
</header>
|
</header>
|
||||||
<nav>
|
<nav>
|
||||||
<!-- main nav here -->
|
<!-- navigation -->
|
||||||
</nav>
|
</nav>
|
||||||
<main id="maincontent"></main>
|
<main id="maincontent" tabindex="-1">
|
||||||
|
<h1><!-- page title --></h1>
|
||||||
|
<!-- content -->
|
||||||
|
</main>
|
||||||
```
|
```
|
||||||
|
|
||||||
```css
|
```css
|
||||||
@@ -86,284 +88,215 @@ A skip link MUST be provided to skip blocks of content that appear across severa
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Common keyboard commands:
|
### Composite widgets (SHOULD)
|
||||||
|
|
||||||
- `Tab` = Move to the next interactive element.
|
If a component uses arrow-key navigation within itself (tabs, listbox, menu-like UI, grid/date picker):
|
||||||
- `Arrow` = Move between elements within a composite component, like a date picker, grid, combobox, listbox, etc.
|
|
||||||
- `Enter` = Activate the currently focused control (button, link, etc.)
|
|
||||||
- `Escape` = Close open surfaces, such as dialogs, menus, listboxes, etc.
|
|
||||||
|
|
||||||
#### Managing focus within components using a roving tabindex
|
- Provide one tab stop for the composite container or one child.
|
||||||
|
- Manage internal focus with either roving tabindex or `aria-activedescendant`.
|
||||||
|
|
||||||
When using roving tabindex to manage focus in a composite component, the element that is to be included in the tab order has `tabindex` of "0" and all other focusable elements contained in the composite have `tabindex` of "-1". The algorithm for the roving tabindex strategy is as follows.
|
Roving tabindex (SHOULD):
|
||||||
|
|
||||||
- On initial load of the composite component, set `tabindex="0"` on the element that will initially be included in the tab order and set `tabindex="-1"` on all other focusable elements it contains.
|
- Exactly one focusable item has `tabindex="0"`; all others are `-1`.
|
||||||
- When the component contains focus and the user presses an arrow key that moves focus within the component:
|
- Arrow keys move focus by swapping tabindex and calling `.focus()`.
|
||||||
- Set `tabindex="-1"` on the element that has `tabindex="0"`.
|
|
||||||
- Set `tabindex="0"` on the element that will become focused as a result of the key event.
|
|
||||||
- Set focus via `element.focus()` on the element that now has `tabindex="0"`.
|
|
||||||
|
|
||||||
#### Managing focus in composites using aria-activedescendant
|
`aria-activedescendant` (SHOULD):
|
||||||
|
|
||||||
- The containing element with an appropriate interactive role should have `tabindex="0"` and `aria-activedescendant="IDREF"` where IDREF matches the ID of the element within the container that is active.
|
- Container has `tabindex="0"` and `aria-activedescendant="IDREF"`.
|
||||||
- Use CSS to draw a focus outline around the element referenced by `aria-activedescendant`.
|
- Arrow keys update `aria-activedescendant`.
|
||||||
- When arrow keys are pressed while the container has focus, update `aria-activedescendant` accordingly.
|
|
||||||
|
|
||||||
### Low vision instructions
|
## Low vision and contrast (MUST)
|
||||||
|
|
||||||
- Prefer dark text on light backgrounds, or light text on dark backgrounds.
|
### Contrast requirements (MUST)
|
||||||
- Do not use light text on light backgrounds or dark text on dark backgrounds.
|
|
||||||
- The contrast of text against the background color must be at least 4.5:1. Large text, must be at least 3:1. All text must have sufficient contrast against its background color.
|
|
||||||
- Large text is defined as 18.5px and bold, or 24px.
|
|
||||||
- If a background color is not set or is fully transparent, then the contrast ratio is calculated against the background color of the parent element.
|
|
||||||
- Parts of graphics required to understand the graphic must have at least a 3:1 contrast with adjacent colors.
|
|
||||||
- Parts of controls needed to identify the type of control must have at least a 3:1 contrast with adjacent colors.
|
|
||||||
- Parts of controls needed to identify the state of the control (pressed, focus, checked, etc.) must have at least a 3:1 contrast with adjacent colors.
|
|
||||||
- Color must not be used as the only way to convey information. E.g., a red border to convey an error state, color coding information, etc. Use text and/or shapes in addition to color to convey information.
|
|
||||||
|
|
||||||
### Screen reader instructions
|
- Text contrast: at least 4.5:1 (large text: 3:1).
|
||||||
|
- Large text is at least 24px regular or 18.66px bold.
|
||||||
|
- Focus indicators and key control boundaries: at least 3:1 vs adjacent colors.
|
||||||
|
- Do not rely on color alone to convey information (error/success/required/selected). Provide text and/or icons with accessible names.
|
||||||
|
|
||||||
- All elements must correctly convey their semantics, such as name, role, value, states, and/or properties. Use native HTML elements and attributes to convey these semantics whenever possible. Otherwise, use appropriate ARIA attributes.
|
### Color generation rules (MUST)
|
||||||
- Use appropriate landmarks and regions. Examples include: `<header>`, `<nav>`, `<main>`, and `<footer>`.
|
|
||||||
- Use headings (e.g., `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h5>`, `<h6>`) to introduce new sections of content. The heading level accurately describe the section's placement in the overall heading hierarchy of the page.
|
|
||||||
- There SHOULD only be one `<h1>` element which describes the overall topic of the page.
|
|
||||||
- Avoid skipping heading levels whenever possible.
|
|
||||||
|
|
||||||
### Voice Access instructions
|
- Do not invent arbitrary colors.
|
||||||
|
- Use project-approved design tokens (CSS variables).
|
||||||
|
- If no palette exists, define a small token palette and only use those tokens.
|
||||||
|
- Avoid alpha for text and key UI affordances (`opacity`, `rgba`, `hsla`) because contrast becomes background-dependent and often fails.
|
||||||
|
- Ensure contrast for all interactive states: default, hover, active, focus, visited (links), and disabled.
|
||||||
|
|
||||||
- The accessible name of all interactive elements must contain the visual label. This is so that voice access users can issue commands like "Click \<label>". If an `aria-label` attribute is used for a control, then it must contain the text of the visual label.
|
### Safe defaults when unsure (SHOULD)
|
||||||
- Interactive elements must have appropriate roles and keyboard behaviors.
|
|
||||||
|
|
||||||
## Instructions for specific patterns
|
- Prefer very dark text on very light backgrounds, or the reverse.
|
||||||
|
- Avoid mid-gray text on white; muted text should still meet 4.5:1.
|
||||||
|
|
||||||
### Form instructions
|
### Tokenized palette contract (SHOULD)
|
||||||
|
|
||||||
- Labels for interactive elements must accurately describe the purpose of the element. E.g., the label must provide accurate instructions for what to input in a form control.
|
- Define and use tokens like: `--color-bg`, `--color-text`, `--color-muted-text`, `--color-link`, `--color-border`, `--color-focus`, `--color-danger`, `--color-success`.
|
||||||
- Headings must accurately describe the topic that they introduce.
|
- Only assign UI colors via these tokens (avoid scattered inline hex values).
|
||||||
- Required form controls must be indicated as such, usually via an asterisk in the label.
|
|
||||||
- Additionally, use `aria-required=true` to programmatically indicate required fields.
|
|
||||||
- Error messages must be provided for invalid form input.
|
|
||||||
- Error messages must describe how to fix the issue.
|
|
||||||
- Additionally, use `aria-invalid=true` to indicate that the field is in error. Remove this attribute when the error is removed.
|
|
||||||
- Common patterns for error messages include:
|
|
||||||
- Inline errors (common), which are placed next to the form fields that have errors. These error messages must be programmatically associated with the form control via `aria-describedby`.
|
|
||||||
- Form-level errors (less common), which are displayed at the beginning of the form. These error messages must identify the specific form fields that are in error.
|
|
||||||
- Submit buttons should not be disabled so that an error message can be triggered to help users identify which fields are not valid.
|
|
||||||
- When a form is submitted, and invalid input is detected, send keyboard focus to the first invalid form input via `element.focus()`.
|
|
||||||
|
|
||||||
### Graphics and images instructions
|
### Verification (MUST)
|
||||||
|
|
||||||
#### All graphics MUST be accounted for
|
Contrast verification is covered by the Final verification checklist.
|
||||||
|
|
||||||
All graphics are included in these instructions. Graphics include, but are not limited to:
|
## High contrast / forced colors mode (MUST)
|
||||||
|
|
||||||
- `<img>` elements.
|
### Support OS-level accessibility features (MUST)
|
||||||
- `<svg>` elements.
|
|
||||||
- Font icons
|
|
||||||
- Emojis
|
|
||||||
|
|
||||||
#### All graphics MUST have the correct role
|
- Never override or disrupt OS accessibility settings.
|
||||||
|
- The UI MUST adapt to High Contrast / Forced Colors mode automatically.
|
||||||
|
- Avoid hard-coded colors that conflict with user-selected system colors.
|
||||||
|
|
||||||
All graphics, regardless of type, have the correct role. The role is either provided by the `<img>` element or the `role='img'` attribute.
|
### Use the `forced-colors` media query when needed (SHOULD)
|
||||||
|
|
||||||
- The `<img>` element does not need a role attribute.
|
Use `@media (forced-colors: active)` only when system defaults are not sufficient.
|
||||||
- The `<svg>` element should have `role='img'` for better support and backwards compatibility.
|
|
||||||
- Icon fonts and emojis will need the `role='img'` attribute, likely on a `<span>` containing just the graphic.
|
|
||||||
|
|
||||||
#### All graphics MUST have appropriate alternative text
|
```css
|
||||||
|
@media (forced-colors: active) {
|
||||||
First, determine if the graphic is informative or decorative.
|
/* Example: Replace box-shadow (suppressed in forced-colors) with a border */
|
||||||
|
.button {
|
||||||
- Informative graphics convey important information not found in elsewhere on the page.
|
border: 2px solid ButtonBorder;
|
||||||
- Decorative graphics do not convey important information, or they contain information found elsewhere on the page.
|
}
|
||||||
|
}
|
||||||
#### Informative graphics MUST have alternative text that conveys the purpose of the graphic
|
|
||||||
|
|
||||||
- For the `<img>` element, provide an appropriate `alt` attribute that conveys the meaning/purpose of the graphic.
|
|
||||||
- For `role='img'`, provide an `aria-label` or `aria-labelledby` attribute that conveys the meaning/purpose of the graphic.
|
|
||||||
- Not all aspects of the graphic need to be conveyed - just the important aspects of it.
|
|
||||||
- Keep the alternative text concise but meaningful.
|
|
||||||
- Avoid using the `title` attribute for alt text.
|
|
||||||
|
|
||||||
#### Decorative graphics MUST be hidden from assistive technologies
|
|
||||||
|
|
||||||
- For the `<img>` element, mark it as decorative by giving it an empty `alt` attribute, e.g., `alt=""`.
|
|
||||||
- For `role='img'`, use `aria-hidden=true`.
|
|
||||||
|
|
||||||
### Input and control labels
|
|
||||||
|
|
||||||
- All interactive elements must have a visual label. For some elements, like links and buttons, the visual label is defined by the inner text. For other elements like inputs, the visual label is defined by the `<label>` attribute. Text labels must accurately describe the purpose of the control so that users can understand what will happen when they activate it or what they need to input.
|
|
||||||
- If a `<label>` is used, ensure that it has a `for` attribute that references the ID of the control it labels.
|
|
||||||
- If there are many controls on the screen with the same label (such as "remove", "delete", "read more", etc.), then an `aria-label` can be used to clarify the purpose of the control so that it is understandable out of context, since screen reader users may jump to the control without reading surrounding static content. E.g., "Remove what" or "read more about {what}".
|
|
||||||
- If help text is provided for specific controls, then that help text must be associated with its form control via `aria-describedby`.
|
|
||||||
|
|
||||||
### Navigation and menus
|
|
||||||
|
|
||||||
#### Good navigation region code example
|
|
||||||
|
|
||||||
```html
|
|
||||||
<nav>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<button aria-expanded="false" tabindex="0">Section 1</button>
|
|
||||||
<ul hidden>
|
|
||||||
<li><a href="..." tabindex="-1">Link 1</a></li>
|
|
||||||
<li><a href="..." tabindex="-1">Link 2</a></li>
|
|
||||||
<li><a href="..." tabindex="-1">Link 3</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<button aria-expanded="false" tabindex="-1">Section 2</button>
|
|
||||||
<ul hidden>
|
|
||||||
<li><a href="..." tabindex="-1">Link 1</a></li>
|
|
||||||
<li><a href="..." tabindex="-1">Link 2</a></li>
|
|
||||||
<li><a href="..." tabindex="-1">Link 3</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Navigation instructions
|
In Forced Colors mode, avoid relying on:
|
||||||
|
|
||||||
- Follow the above code example where possible.
|
- Box shadows
|
||||||
- Navigation menus should not use the `menu` role or `menubar` role. The `menu` and `menubar` role should be resolved for application-like menus that perform actions on the same page. Instead, this should be a `<nav>` that contains a `<ul>` with links.
|
- Background images
|
||||||
- When expanding or collapsing a navigation menu, toggle the `aria-expanded` property.
|
- Decorative gradients
|
||||||
- Use the roving tabindex pattern to manage focus within the navigation. Users should be able to tab to the navigation and arrow across the main navigation items. Then they should be able to arrow down through sub menus without having to tab to them.
|
|
||||||
- Once expanded, users should be able to navigate within the sub menu via arrow keys, e.g., up and down arrow keys.
|
|
||||||
- The `escape` key could close any expanded menus.
|
|
||||||
|
|
||||||
### Page Title
|
### Respect user color schemes in forced colors (MUST)
|
||||||
|
|
||||||
The page title:
|
- Use system color keywords (e.g., `ButtonText`, `ButtonBorder`, `CanvasText`, `Canvas`).
|
||||||
|
- Do not use fixed hex/RGB colors inside `@media (forced-colors: active)`.
|
||||||
|
|
||||||
- MUST be defined in the `<title>` element in the `<head>`.
|
### Do not disable forced colors (MUST)
|
||||||
- MUST describe the purpose of the page.
|
|
||||||
- SHOULD be unique for each page.
|
|
||||||
- SHOULD front-load unique information.
|
|
||||||
- SHOULD follow the format of "[Describe unique page] - [section title] - [site title]"
|
|
||||||
|
|
||||||
### Table and Grid Accessibility Acceptance Criteria
|
- Do not use `forced-color-adjust: none` unless absolutely necessary and explicitly justified.
|
||||||
|
- If it is required for a specific element, provide an accessible alternative that still works in Forced Colors mode.
|
||||||
|
|
||||||
#### Column and row headers are programmatically associated
|
### Icons (MUST)
|
||||||
|
|
||||||
Column and row headers MUST be programmatically associated for each cell. In HTML, this is done by using `<th>` elements. Column headers MUST be defined in the first table row `<tr>`. Row headers must defined in the row they are for. Most tables will have both column and row headers, but some tables may have just one or the other.
|
- Icons MUST adapt to text color.
|
||||||
|
- Prefer `currentColor` for SVG icon fills/strokes; avoid embedding fixed colors inside SVGs.
|
||||||
|
|
||||||
#### Good example - table with both column and row headers:
|
```css
|
||||||
|
svg {
|
||||||
```html
|
fill: currentColor;
|
||||||
<table>
|
stroke: currentColor;
|
||||||
<tr>
|
}
|
||||||
<th>Header 1</th>
|
|
||||||
<th>Header 2</th>
|
|
||||||
<th>Header 3</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Row Header 1</th>
|
|
||||||
<td>Cell 1</td>
|
|
||||||
<td>Cell 2</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Row Header 2</th>
|
|
||||||
<td>Cell 1</td>
|
|
||||||
<td>Cell 2</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Good example - table with just column headers:
|
## Reflow (WCAG 2.2 SC 1.4.10) (MUST)
|
||||||
|
|
||||||
```html
|
### Goal (MUST)
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>Header 1</th>
|
|
||||||
<th>Header 2</th>
|
|
||||||
<th>Header 3</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Cell 1</td>
|
|
||||||
<td>Cell 2</td>
|
|
||||||
<td>Cell 3</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Cell 1</td>
|
|
||||||
<td>Cell 2</td>
|
|
||||||
<td>Cell 3</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Bad example - calendar grid with partial semantics:
|
At a width equivalent to 320 CSS px, all content and functionality MUST remain available without requiring two-directional scrolling.
|
||||||
|
|
||||||
The following example is a date picker or calendar grid.
|
### Core principles (MUST)
|
||||||
|
|
||||||
```html
|
- Preserve information and function: nothing essential is removed, obscured, or truncated.
|
||||||
<div role="grid">
|
- At narrow widths, multi-column layouts MUST stack into a single column; text MUST wrap; controls SHOULD rearrange vertically.
|
||||||
<div role="columnheader">Sun</div>
|
- Users SHOULD NOT need to scroll left/right to read multi-line text.
|
||||||
<div role="columnheader">Mon</div>
|
- If content is collapsed in the narrow layout, the full content/function MUST be available within 1 click (e.g., overflow menu, dialog, tooltip).
|
||||||
<div role="columnheader">Tue</div>
|
|
||||||
<div role="columnheader">Wed</div>
|
|
||||||
<div role="columnheader">Thu</div>
|
|
||||||
<div role="columnheader">Fri</div>
|
|
||||||
<div role="columnheader">Sat</div>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Sunday, June 1, 2025">1</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Monday, June 2, 2025">2</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Tuesday, June 3, 2025">3</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Wednesday, June 4, 2025">4</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Thursday, June 5, 2025">5</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Friday, June 6, 2025">6</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Saturday, June 7, 2025">7</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Sunday, June 8, 2025">8</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Monday, June 9, 2025">9</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Tuesday, June 10, 2025">10</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Wednesday, June 11, 2025">11</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Thursday, June 12, 2025">12</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Friday, June 13, 2025">13</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Saturday, June 14, 2025">14</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Sunday, June 15, 2025">15</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Monday, June 16, 2025">16</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Tuesday, June 17, 2025">17</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Wednesday, June 18, 2025">18</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Thursday, June 19, 2025">19</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Friday, June 20, 2025">20</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Saturday, June 21, 2025">21</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Sunday, June 22, 2025">22</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Monday, June 23, 2025">23</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Tuesday, June 24, 2025" aria-current="date">24</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Wednesday, June 25, 2025">25</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Thursday, June 26, 2025">26</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Friday, June 27, 2025">27</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Saturday, June 28, 2025">28</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Sunday, June 29, 2025">29</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Monday, June 30, 2025">30</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Tuesday, July 1, 2025" aria-disabled="true">1</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Wednesday, July 2, 2025" aria-disabled="true">2</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Thursday, July 3, 2025" aria-disabled="true">3</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Friday, July 4, 2025" aria-disabled="true">4</button>
|
|
||||||
<button role="gridcell" tabindex="-1" aria-label="Saturday, July 5, 2025" aria-disabled="true">5</button>
|
|
||||||
</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
##### The good:
|
### Engineering requirements (MUST)
|
||||||
|
|
||||||
- It uses `role="grid"` to indicate that it is a grid.
|
- Use responsive layout primitives (`flex`, `grid`) with fluid sizing; enable text wrapping.
|
||||||
- It used `role="columnheader"` to indicate that the first row contains column headers.
|
- Avoid fixed widths that force horizontal scrolling at 320px.
|
||||||
- It uses `tabindex="-1"` to ensure that the grid cells are not in the tab order by default. Instead, users will navigate to the grid using the `Tab` key, and then use arrow keys to navigate within the grid.
|
- Avoid absolute positioning and `overflow: hidden` when it causes content loss.
|
||||||
|
- Media and containers MUST not overflow the viewport at 320px (for example, prefer `max-width: 100%` for images/video/canvas/iframes).
|
||||||
|
- In flex/grid layouts, ensure children can shrink/wrap (common fix: `min-width: 0` on flex/grid children).
|
||||||
|
- Handle long strings (URLs, tokens) without forcing overflow (common fix: `overflow-wrap: anywhere` or equivalent).
|
||||||
|
- Ensure all interactive elements remain visible, reachable, and operable at 320px.
|
||||||
|
|
||||||
##### The bad:
|
### Exceptions (SHOULD)
|
||||||
|
|
||||||
- `role=gridcell` elements are not nested within `role=row` elements. Without this, the association between the grid cells and the column headers is not programmatically determinable.
|
If a component truly requires a two-dimensional layout for meaning/usage (e.g., large data tables, maps, diagrams, charts, games, presentations), allow horizontal scrolling only at the component level.
|
||||||
|
|
||||||
#### Prefer simple tables and grids
|
- The page as a whole MUST still reflow.
|
||||||
|
- The component MUST remain fully usable (all content reachable; controls operable).
|
||||||
|
|
||||||
Simple tables have just one set of column and/or row headers. Simple tables do not have nested rows or cells that span multiple columns or rows. Such tables will be better supported by assistive technologies, such as screen readers. Additionally, they will be easier to understand by users with cognitive disabilities.
|
## Controls and labels
|
||||||
|
|
||||||
Complex tables and grids have multiple levels of column and/or row headers, or cells that span multiple columns or rows. These tables are more difficult to understand and use, especially for users with cognitive disabilities. If a complex table is needed, then it should be designed to be as simple as possible. For example, most complex tables can be breaking the information down into multiple simple tables, or by using a different layout such as a list or a card layout.
|
### Visible labels (MUST)
|
||||||
|
|
||||||
#### Use tables for static information
|
- Every interactive element has a visible label.
|
||||||
|
- The label cannot disappear while entering text or after the field has a value.
|
||||||
|
|
||||||
Tables should be used for static information that is best represented in a tabular format. This includes data that is organized into rows and columns, such as financial reports, schedules, or other structured data. Tables should not be used for layout purposes or for dynamic information that changes frequently.
|
### Voice access (MUST)
|
||||||
|
|
||||||
#### Use grids for dynamic information
|
- The accessible name of each interactive element MUST contain the visible label.
|
||||||
|
- If using `aria-label`, include the visual label text.
|
||||||
|
- If multiple controls share the same visible label (e.g., many “Remove” buttons), use an `aria-label` that keeps the visible label text and adds context (e.g., “Remove item: Socks”).
|
||||||
|
|
||||||
Grids should be used for dynamic information that is best represented in a grid format. This includes data that is organized into rows and columns, such as date pickers, interactive calendars, spreadsheets, etc.
|
## Forms
|
||||||
|
|
||||||
|
### Labels and help text (MUST)
|
||||||
|
|
||||||
|
- Every form control has a programmatic label.
|
||||||
|
- Prefer `<label for="...">`.
|
||||||
|
- Labels describe the input purpose.
|
||||||
|
- If help text exists, associate it with `aria-describedby`.
|
||||||
|
|
||||||
|
### Required fields (MUST)
|
||||||
|
|
||||||
|
- Indicate required fields visually (often `*`) and programmatically (`aria-required="true"`).
|
||||||
|
|
||||||
|
### Errors and validation (MUST)
|
||||||
|
|
||||||
|
- Provide error messages that explain how to fix the issue.
|
||||||
|
- Use `aria-invalid="true"` for invalid fields; remove it when valid.
|
||||||
|
- Associate inline errors with the field via `aria-describedby`.
|
||||||
|
- Submit buttons SHOULD NOT be disabled solely to prevent submission.
|
||||||
|
- On submit with invalid input, focus the first invalid control.
|
||||||
|
|
||||||
|
## Graphics and images
|
||||||
|
|
||||||
|
All graphics include `img`, `svg`, icon fonts, and emojis.
|
||||||
|
|
||||||
|
- Informative graphics MUST have meaningful alternatives.
|
||||||
|
- `img`: use `alt`.
|
||||||
|
- `svg`: prefer `role="img"` and `aria-label`/`aria-labelledby`.
|
||||||
|
- Decorative graphics MUST be hidden.
|
||||||
|
- `img`: `alt=""`.
|
||||||
|
- Other: `aria-hidden="true"`.
|
||||||
|
|
||||||
|
## Navigation and menus
|
||||||
|
|
||||||
|
- Use semantic navigation: `<nav>` with lists and links.
|
||||||
|
- Do not use `role="menu"` / `role="menubar"` for site navigation.
|
||||||
|
- For expandable navigation:
|
||||||
|
- Toggle `aria-expanded`.
|
||||||
|
- `Escape` MAY close open menus.
|
||||||
|
|
||||||
|
## Tables and grids
|
||||||
|
|
||||||
|
### Tables for static data (MUST)
|
||||||
|
|
||||||
|
- Use `<table>` for static tabular data.
|
||||||
|
- Use `<th>` to associate headers.
|
||||||
|
- Column headers are in the first row.
|
||||||
|
- Row headers (when present) use `<th>` in each row.
|
||||||
|
|
||||||
|
### Grids for dynamic UIs (SHOULD)
|
||||||
|
|
||||||
|
- Use grid roles only for truly interactive/dynamic experiences.
|
||||||
|
- If using `role="grid"`, grid cells MUST be nested in rows so header/cell relationships are determinable.
|
||||||
|
- Use arrow navigation to navigate within the grid.
|
||||||
|
|
||||||
|
## Final verification checklist (MUST)
|
||||||
|
|
||||||
|
Before finalizing output, explicitly verify:
|
||||||
|
|
||||||
|
- Structure and semantics: landmarks, headings, and one `h1` for the page topic.
|
||||||
|
- Keyboard and focus: operable controls, visible focus, predictable tab order, no traps, skip link works.
|
||||||
|
- Controls and labels: visible labels present and included in accessible names.
|
||||||
|
- Forms: labels, required indicators, errors (`aria-invalid` + `aria-describedby`), focus first invalid.
|
||||||
|
- Contrast: meets 4.5:1 / 3:1 thresholds, focus/boundaries meet 3:1, color not the only cue.
|
||||||
|
- Forced colors: does not break OS High Contrast / Forced Colors; uses system colors in `forced-colors: active`.
|
||||||
|
- Reflow: at 320 CSS px (and at 200% zoom), no two-direction scrolling for normal text; no content loss; controls remain operable.
|
||||||
|
- Graphics: informative alternatives; decorative graphics hidden.
|
||||||
|
- Tables/grids: tables use `<th>`; grids (when needed) are structured with rows and cells.
|
||||||
|
|
||||||
|
## Final note
|
||||||
|
|
||||||
|
Generate the HTML with accessibility in mind, but accessibility issues may still exist; manual review and testing (for example with Accessibility Insights) is still recommended.
|
||||||
|
|||||||
85
skills/create-web-form/SKILL.md
Normal file
85
skills/create-web-form/SKILL.md
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
---
|
||||||
|
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
|
||||||
|
|
||||||
|
### 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
|
||||||
|
- `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.
|
||||||
@@ -1148,8 +1148,7 @@ gh pr comment 123 --delete 456789
|
|||||||
gh pr review 123
|
gh pr review 123
|
||||||
|
|
||||||
# Approve PR
|
# Approve PR
|
||||||
gh pr review 123 --approve \
|
gh pr review 123 --approve --body "LGTM!"
|
||||||
--approve-body "LGTM!"
|
|
||||||
|
|
||||||
# Request changes
|
# Request changes
|
||||||
gh pr review 123 --request-changes \
|
gh pr review 123 --request-changes \
|
||||||
|
|||||||
@@ -1,56 +1,113 @@
|
|||||||
---
|
---
|
||||||
name: microsoft-docs
|
name: microsoft-docs
|
||||||
description: Query official Microsoft documentation to understand concepts, find tutorials, and learn how services work. Use for Azure, .NET, Microsoft 365, Windows, Power Platform, and all Microsoft technologies. Get accurate, current information from learn.microsoft.com and other official Microsoft websites—architecture overviews, quickstarts, configuration guides, limits, and best practices.
|
description: 'Query official Microsoft documentation to find concepts, tutorials, and code examples across Azure, .NET, Agent Framework, Aspire, VS Code, GitHub, and more. Uses Microsoft Learn MCP as the default, with Context7 and Aspire MCP for content that lives outside learn.microsoft.com.'
|
||||||
compatibility: Requires Microsoft Learn MCP Server (https://learn.microsoft.com/api/mcp)
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Microsoft Docs
|
# Microsoft Docs
|
||||||
|
|
||||||
## Tools
|
Research skill for the Microsoft technology ecosystem. Covers learn.microsoft.com and documentation that lives outside it (VS Code, GitHub, Aspire, Agent Framework repos).
|
||||||
|
|
||||||
| Tool | Use For |
|
---
|
||||||
|
|
||||||
|
## Default: Microsoft Learn MCP
|
||||||
|
|
||||||
|
Use these tools for **everything on learn.microsoft.com** — Azure, .NET, M365, Power Platform, Agent Framework, Semantic Kernel, Windows, and more. This is the primary tool for the vast majority of Microsoft documentation queries.
|
||||||
|
|
||||||
|
| Tool | Purpose |
|
||||||
|------|---------|
|
|------|---------|
|
||||||
| `microsoft_docs_search` | Find documentation—concepts, guides, tutorials, configuration |
|
| `microsoft_docs_search` | Search learn.microsoft.com — concepts, guides, tutorials, configuration |
|
||||||
| `microsoft_docs_fetch` | Get full page content (when search excerpts aren't enough) |
|
| `microsoft_code_sample_search` | Find working code snippets from Learn docs. Pass `language` (`python`, `csharp`, etc.) for best results |
|
||||||
|
| `microsoft_docs_fetch` | Get full page content from a specific URL (when search excerpts aren't enough) |
|
||||||
|
|
||||||
## When to Use
|
Use `microsoft_docs_fetch` after search when you need complete tutorials, all config options, or when search excerpts are truncated.
|
||||||
|
|
||||||
- **Understanding concepts** — "How does Cosmos DB partitioning work?"
|
---
|
||||||
- **Learning a service** — "Azure Functions overview", "Container Apps architecture"
|
|
||||||
- **Finding tutorials** — "quickstart", "getting started", "step-by-step"
|
|
||||||
- **Configuration options** — "App Service configuration settings"
|
|
||||||
- **Limits & quotas** — "Azure OpenAI rate limits", "Service Bus quotas"
|
|
||||||
- **Best practices** — "Azure security best practices"
|
|
||||||
|
|
||||||
## Query Effectiveness
|
## Exceptions: When to Use Other Tools
|
||||||
|
|
||||||
Good queries are specific:
|
The following categories live **outside** learn.microsoft.com. Use the specified tool instead.
|
||||||
|
|
||||||
|
### .NET Aspire — Use Aspire MCP Server (preferred) or Context7
|
||||||
|
|
||||||
|
Aspire docs live on **aspire.dev**, not Learn. The best tool depends on your Aspire CLI version:
|
||||||
|
|
||||||
|
**CLI 13.2+** (recommended) — The Aspire MCP server includes built-in docs search tools:
|
||||||
|
|
||||||
|
| MCP Tool | Description |
|
||||||
|
|----------|-------------|
|
||||||
|
| `list_docs` | Lists all available documentation from aspire.dev |
|
||||||
|
| `search_docs` | Weighted lexical search across aspire.dev content |
|
||||||
|
| `get_doc` | Retrieves a specific document by slug |
|
||||||
|
|
||||||
|
These ship in Aspire CLI 13.2 ([PR #14028](https://github.com/dotnet/aspire/pull/14028)). To update: `aspire update --self --channel daily`. Ref: https://davidpine.dev/posts/aspire-docs-mcp-tools/
|
||||||
|
|
||||||
|
**CLI 13.1** — The MCP server provides integration lookup (`list_integrations`, `get_integration_docs`) but **not** docs search. Fall back to Context7:
|
||||||
|
|
||||||
|
| Library ID | Use for |
|
||||||
|
|---|---|
|
||||||
|
| `/microsoft/aspire.dev` | Primary — guides, integrations, CLI reference, deployment |
|
||||||
|
| `/dotnet/aspire` | Runtime source — API internals, implementation details |
|
||||||
|
| `/communitytoolkit/aspire` | Community integrations — Go, Java, Node.js, Ollama |
|
||||||
|
|
||||||
|
### VS Code — Use Context7
|
||||||
|
|
||||||
|
VS Code docs live on **code.visualstudio.com**, not Learn.
|
||||||
|
|
||||||
|
| Library ID | Use for |
|
||||||
|
|---|---|
|
||||||
|
| `/websites/code_visualstudio` | User docs — settings, features, debugging, remote dev |
|
||||||
|
| `/websites/code_visualstudio_api` | Extension API — webviews, TreeViews, commands, contribution points |
|
||||||
|
|
||||||
|
### GitHub — Use Context7
|
||||||
|
|
||||||
|
GitHub docs live on **docs.github.com** and **cli.github.com**.
|
||||||
|
|
||||||
|
| Library ID | Use for |
|
||||||
|
|---|---|
|
||||||
|
| `/websites/github_en` | Actions, API, repos, security, admin, Copilot |
|
||||||
|
| `/websites/cli_github` | GitHub CLI (`gh`) commands and flags |
|
||||||
|
|
||||||
|
### Agent Framework — Use Learn MCP + Context7
|
||||||
|
|
||||||
|
Agent Framework tutorials are on learn.microsoft.com (use `microsoft_docs_search`), but the **GitHub repo** has API-level detail that is often ahead of published docs — particularly DevUI REST API reference, CLI options, and .NET integration.
|
||||||
|
|
||||||
|
| Library ID | Use for |
|
||||||
|
|---|---|
|
||||||
|
| `/websites/learn_microsoft_en-us_agent-framework` | Tutorials — DevUI guides, tracing, workflow orchestration |
|
||||||
|
| `/microsoft/agent-framework` | API detail — DevUI REST endpoints, CLI flags, auth, .NET `AddDevUI`/`MapDevUI` |
|
||||||
|
|
||||||
|
**DevUI tip:** Query the Learn website source for how-to guides, then the repo source for API-level specifics (endpoint schemas, proxy config, auth tokens).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Context7 Setup
|
||||||
|
|
||||||
|
For any Context7 query, resolve the library ID first (one-time per session):
|
||||||
|
|
||||||
|
1. Call `mcp_context7_resolve-library-id` with the technology name
|
||||||
|
2. Call `mcp_context7_query-docs` with the returned library ID and a specific query
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Writing Effective Queries
|
||||||
|
|
||||||
|
Be specific — include version, intent, and language:
|
||||||
|
|
||||||
```
|
```
|
||||||
# ❌ Too broad
|
# ❌ Too broad
|
||||||
"Azure Functions"
|
"Azure Functions"
|
||||||
|
"agent framework"
|
||||||
|
|
||||||
# ✅ Specific
|
# ✅ Specific
|
||||||
"Azure Functions Python v2 programming model"
|
"Azure Functions Python v2 programming model"
|
||||||
"Cosmos DB partition key design best practices"
|
"Cosmos DB partition key design best practices"
|
||||||
"Container Apps scaling rules KEDA"
|
"GitHub Actions workflow_dispatch inputs matrix strategy"
|
||||||
|
"Aspire AddUvicornApp Python FastAPI integration"
|
||||||
|
"DevUI serve agents tracing OpenTelemetry directory discovery"
|
||||||
|
"Agent Framework workflow conditional edges branching handoff"
|
||||||
```
|
```
|
||||||
|
|
||||||
Include context:
|
Include context:
|
||||||
- **Version** when relevant (`.NET 8`, `EF Core 8`)
|
- **Version** when relevant (`.NET 8`, `Aspire 13`, `VS Code 1.96`)
|
||||||
- **Task intent** (`quickstart`, `tutorial`, `overview`, `limits`)
|
- **Task intent** (`quickstart`, `tutorial`, `overview`, `limits`, `API reference`)
|
||||||
- **Platform** for multi-platform docs (`Linux`, `Windows`)
|
- **Language** for polyglot docs (`Python`, `TypeScript`, `C#`)
|
||||||
|
|
||||||
## When to Fetch Full Page
|
|
||||||
|
|
||||||
Fetch after search when:
|
|
||||||
- **Tutorials** — need complete step-by-step instructions
|
|
||||||
- **Configuration guides** — need all options listed
|
|
||||||
- **Deep dives** — user wants comprehensive coverage
|
|
||||||
- **Search excerpt is cut off** — full context needed
|
|
||||||
|
|
||||||
## Why Use This
|
|
||||||
|
|
||||||
- **Accuracy** — live docs, not training data that may be outdated
|
|
||||||
- **Completeness** — tutorials have all steps, not fragments
|
|
||||||
- **Authority** — official Microsoft documentation
|
|
||||||
|
|||||||
Reference in New Issue
Block a user