From ab8787b505f6d38d21b3c6f9ee59287eecb2384e Mon Sep 17 00:00:00 2001 From: Chris McKee Date: Fri, 6 Feb 2026 10:03:29 -0600 Subject: [PATCH 01/17] feat: Expand microsoft-docs skill with Agent Framework, DevUI, and Semantic Kernel coverage Major improvements to the microsoft-docs skill: - Add Microsoft Agent Framework section with two Context7 sources: /websites/learn_microsoft_en-us_agent-framework (tutorials, 2282 snippets) /microsoft/agent-framework (GitHub repo API detail, 1177 snippets) - Add comprehensive DevUI workflow reference covering installation, programmatic launch, directory discovery, tracing, OpenAI-compatible API, OpenAI proxy, authentication, UI modes, .NET integration, and external observability export - Add Semantic Kernel section with three quality-ranked sources covering Learn docs, agent framework subset, and GitHub repo - Add guidance on when GitHub repo sources beat published docs (DevUI API reference, .NET integration, extension samples) - Expand decision table with agent framework scenarios - Add agent framework query examples for DevUI, SK, and workflows - Highlight microsoft_code_sample_search with language filter for working code snippets Tested all sources against identical queries to verify quality rankings. --- docs/README.skills.md | 2 +- skills/microsoft-docs/SKILL.md | 213 +++++++++++++++++++++++++++++---- 2 files changed, 194 insertions(+), 21 deletions(-) diff --git a/docs/README.skills.md b/docs/README.skills.md index c2c3090f..7c3fa2e1 100644 --- a/docs/README.skills.md +++ b/docs/README.skills.md @@ -43,7 +43,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 | | [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-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 and Microsoft-adjacent documentation to understand concepts, find tutorials, and get code examples. Covers Azure, .NET, Agent Framework, Semantic Kernel, DevUI, Aspire, VS Code, GitHub, Microsoft 365, Windows, and Power Platform using Microsoft Learn MCP and Context7 for comprehensive lookup across learn.microsoft.com, code.visualstudio.com, docs.github.com, aspire.dev, and GitHub source repos. | 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`
`references/component-patterns.md`
`references/platform-guidelines.md`
`references/setup-troubleshooting.md` | | [plantuml-ascii](../skills/plantuml-ascii/SKILL.md) | Generate ASCII art diagrams using PlantUML text mode. Use when user asks to create ASCII diagrams, text-based diagrams, terminal-friendly diagrams, or mentions plantuml ascii, text diagram, ascii art diagram. Supports: Converting PlantUML diagrams to ASCII art, Creating sequence diagrams, class diagrams, flowcharts in ASCII format, Generating Unicode-enhanced ASCII art with -utxt flag | None | diff --git a/skills/microsoft-docs/SKILL.md b/skills/microsoft-docs/SKILL.md index 92f523b7..d5511dfc 100644 --- a/skills/microsoft-docs/SKILL.md +++ b/skills/microsoft-docs/SKILL.md @@ -1,26 +1,143 @@ --- 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. -compatibility: Requires Microsoft Learn MCP Server (https://learn.microsoft.com/api/mcp) +description: 'Query official Microsoft and Microsoft-adjacent documentation to understand concepts, find tutorials, and get code examples. Covers Azure, .NET, Agent Framework, Semantic Kernel, DevUI, Aspire, VS Code, GitHub, Microsoft 365, Windows, and Power Platform using Microsoft Learn MCP and Context7 for comprehensive lookup across learn.microsoft.com, code.visualstudio.com, docs.github.com, aspire.dev, and GitHub source repos.' --- # Microsoft Docs +A unified documentation research skill for the full Microsoft technology ecosystem — including technologies like VS Code, GitHub, and Agent Framework repos that live outside or ahead of learn.microsoft.com. + ## Tools +### Microsoft Learn MCP Server + | Tool | Use For | |------|---------| -| `microsoft_docs_search` | Find documentation—concepts, guides, tutorials, configuration | -| `microsoft_docs_fetch` | Get full page content (when search excerpts aren't enough) | +| `microsoft_docs_search` | Find documentation on learn.microsoft.com — concepts, guides, tutorials, configuration | +| `microsoft_code_sample_search` | Find **working code snippets** from official Microsoft Learn docs. Especially strong for Agent Framework, Semantic Kernel, DevUI, and Azure SDK examples. Pass `language` parameter (`python`, `csharp`) for best results. | +| `microsoft_docs_fetch` | Get full page content from a specific Microsoft docs URL (when search excerpts aren't enough) | -## When to Use +### Context7 (broader coverage) -- **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" +Context7 indexes both **websites** and **GitHub repos**, giving access to documentation that the Microsoft Learn MCP server cannot reach — including VS Code docs, GitHub docs, Aspire.dev, GitHub CLI, and README-level content from source repos that is often ahead of published docs. + +| Tool | Use For | +|------|---------| +| `mcp_context7_resolve-library-id` | Find the Context7 library ID for a technology (one-time per session) | +| `mcp_context7_query-docs` | Query docs with a specific library ID — returns code snippets, explanations, and source links in a single call | + +### When GitHub Repo Sources (Context7) Beat Published Docs + +Context7 indexes GitHub repo README files, which often contain API-level detail, CLI references, and advanced config that hasn't been published to learn.microsoft.com yet. This is especially true for: + +- **DevUI** — the repo README (`/microsoft/agent-framework`) has complete API reference (endpoints, parameters, response schemas), OpenAI proxy config, and auth setup that the Learn page summarizes +- **Agent Framework .NET** — the repo has `Microsoft.Agents.AI.DevUI` integration code for ASP.NET Core before it appears on Learn +- **Extension samples** — `/microsoft/vscode-extension-samples` has working projects not always linked from the VS Code API docs + +**Rule of thumb:** query the **website source** for tutorials and concepts, then the **repo source** for API-level detail and the latest features. + +## When to Use Which Tool + +| Scenario | Best Tool | Why | +|----------|-----------|-----| +| Azure services, .NET, M365, Power Platform | `microsoft_docs_search` | Direct access to learn.microsoft.com | +| Code samples for any Learn topic | `microsoft_code_sample_search` | Returns up to 20 working code snippets with links. Filter by language. | +| Agent Framework — tutorials, concepts | `microsoft_docs_search` + Context7 Learn | Polished guides on learn.microsoft.com | +| Agent Framework — DevUI setup, API, CLI | Context7 `/microsoft/agent-framework` | GitHub repo has detailed DevUI README with full API reference | +| Agent Framework — DevUI tracing, directory discovery | Context7 `/websites/learn_microsoft_en-us_agent-framework` | Learn website has step-by-step guides | +| Semantic Kernel — agents, plugins, orchestration | Context7 `/websites/learn_microsoft_en-us_semantic-kernel` + `microsoft_code_sample_search` | Learn has the best SK docs; code sample search excels here | +| Semantic Kernel — source code, ADRs, design docs | Context7 `/microsoft/semantic-kernel` | GitHub repo has samples and architectural decisions | +| VS Code features, settings, shortcuts | Context7 `/websites/code_visualstudio` | VS Code docs live on code.visualstudio.com, not Learn | +| VS Code extension development / API | Context7 `/websites/code_visualstudio_api` | Extension API docs are separate from user docs | +| GitHub Actions, repos, API, features | Context7 `/websites/github_en` | GitHub docs live on docs.github.com | +| GitHub CLI (gh) | Context7 `/websites/cli_github` | CLI reference lives on cli.github.com | +| .NET Aspire (AppHost, integrations, CLI) | Context7 `/microsoft/aspire.dev` | Aspire docs live on aspire.dev, not Learn | +| Aspire community integrations (Go, Java) | Context7 `/communitytoolkit/aspire` | Community Toolkit is a separate repo | +| Need full tutorial with all steps | `microsoft_docs_fetch` | Gets complete page content | + +## Context7 Library Reference + +Call `mcp_context7_resolve-library-id` once per session to confirm IDs. Below are tested, quality-ranked sources. + +### Agent Frameworks + +#### Microsoft Agent Framework + +| Library ID | Snippets | Score | Coverage | +|---|---|---|---| +| `/websites/learn_microsoft_en-us_agent-framework` | 2,282 | 81.2 | **Primary for tutorials** — DevUI guides, directory discovery, tracing, AG-UI integration, workflow orchestration | +| `/microsoft/agent-framework` | 1,177 | — | **Primary for API detail** — DevUI README (full REST API, CLI flags, auth, OpenAI proxy), .NET DevUI integration, samples | + +The **Learn website** source has polished tutorials and conceptual docs. The **GitHub repo** source has README-level detail that is often ahead of published docs — particularly the DevUI REST API reference, advanced CLI options, and .NET `Microsoft.Agents.AI.DevUI` package setup. + +**Use both** for comprehensive Agent Framework coverage: query the website source for "how to" guides, then the repo source for API-level specifics. + +##### DevUI Workflow + +DevUI is a sample app for running and debugging agents/workflows interactively. Key topics: + +1. **Installation**: `pip install agent-framework-devui --pre` +2. **Programmatic launch**: `serve(entities=[agent], auto_open=True)` — registers agents in-memory +3. **Directory discovery**: `devui ./agents --port 8080` — auto-discovers agents/workflows from `__init__.py` files +4. **Tracing**: `devui ./agents --tracing` or `serve(entities=[agent], tracing_enabled=True)` — enables OpenTelemetry traces visible in the debug panel +5. **OpenAI-compatible API**: `POST /v1/responses` with `metadata.entity_id` — use with OpenAI Python SDK +6. **OpenAI proxy**: Set `X-Proxy-Backend: openai` header to proxy requests through DevUI (keeps API key server-side) +7. **Authentication**: `devui ./agents --auth --auth-token "token"` — Bearer token auth +8. **UI modes**: `--mode developer` (default, full debug) vs `--mode user` (simplified, restricted) +9. **.NET integration**: `builder.AddDevUI()` + `app.MapDevUI()` in ASP.NET Core (development only) +10. **Export to external observability**: Set `OTLP_ENDPOINT` to send traces to Jaeger, Zipkin, Azure Monitor, Datadog + +**Best query strategy for DevUI:** +- Use `microsoft_code_sample_search` with `language: "python"` for working DevUI code +- Use Context7 `/microsoft/agent-framework` for the DevUI REST API reference +- Use Context7 `/websites/learn_microsoft_en-us_agent-framework` for directory structure and tracing guides + +#### Semantic Kernel + +| Library ID | Snippets | Score | Coverage | +|---|---|---|---| +| `/websites/learn_microsoft_en-us_semantic-kernel` | 4,909 | 69.5 | **Primary** — agents, plugins, orchestration, function calling, migration guides | +| `/websites/learn_microsoft_en-us_semantic-kernel_frameworks_agent` | 932 | 76.4 | Agent framework subset — ChatCompletionAgent, AgentGroupChat, orchestration patterns | +| `/microsoft/semantic-kernel` | 2,950 | 74.7 | GitHub repo — samples, ADRs, design documents, process integration | + +**Use the Learn website source** for Semantic Kernel tutorials and plugin setup. **Use the agent framework subset** for focused agent orchestration queries. **Use the GitHub repo** for sample code, architectural decisions, and advanced patterns (e.g., `GettingStartedWithProcesses`). + +### Azure & .NET (learn.microsoft.com) + +| Library ID | Snippets | Score | Coverage | +|---|---|---|---| +| `/websites/learn_microsoft_en-us_azure` | 164,912 | 73.8 | All Azure services — compute, storage, networking, AI, databases | +| `/microsoftdocs/azure-docs` | 61,791 | 76.7 | Azure docs GitHub repo — higher quality score | +| `/websites/learn_microsoft_en-us` | 158,360 | 45.4 | All of Microsoft Learn — broadest but lower precision | +| `/websites/learn_microsoft_en-us_dotnet_azure` | 1,156 | — | Azure SDK for .NET developers specifically | + +### .NET Aspire + +| Library ID | Snippets | Score | Coverage | +|---|---|---|---| +| `/microsoft/aspire.dev` | 1,865 | 73.0 | **Primary** — official docs site repo, best quality, full Aspire 13+ coverage | +| `/websites/aspire_dev` | 31,845 | 71.6 | Website crawl — massive but includes multilingual duplicates | +| `/dotnet/aspire` | 1,185 | 71.5 | Runtime source — API internals, playground examples | +| `/communitytoolkit/aspire` | 311 | 64.2 | Community integrations — Golang, Java, Node.js, Vite, Ollama | +| `/dotnet/docs-aspire` | 482 | 71.4 | **Legacy** — being superseded by aspire.dev, avoid for tutorials | + +### Visual Studio Code + +| Library ID | Snippets | Score | Coverage | +|---|---|---|---| +| `/websites/code_visualstudio` | 6,288 | 80.4 | **Primary** — user docs, settings, features, debugging, remote dev | +| `/websites/code_visualstudio_api` | 1,681 | 65.4 | Extension API — webviews, TreeViews, commands, contribution points | +| `/microsoft/vscode-docs` | 8,289 | 87.9 | Docs repo — highest score, markdown source files | +| `/microsoft/vscode-extension-samples` | 320 | 82.4 | Extension samples — working code examples | + +### GitHub + +| Library ID | Snippets | Score | Coverage | +|---|---|---|---| +| `/websites/github_en` | 43,828 | 66.2 | **Primary** — Actions, API, repos, security, admin, Copilot | +| `/github/docs` | 24,544 | 73.7 | Docs repo — markdown source, higher quality score | +| `/websites/cli_github` | 386 | 83.2 | GitHub CLI reference — gh commands, flags, examples | +| `/websites/cli_github_manual` | 478 | 44.0 | CLI manual — alternative, lower score | ## Query Effectiveness @@ -29,28 +146,84 @@ Good queries are specific: ``` # ❌ Too broad "Azure Functions" +"VS Code extensions" +"agent framework" # ✅ Specific "Azure Functions Python v2 programming model" "Cosmos DB partition key design best practices" -"Container Apps scaling rules KEDA" +"VS Code webview API onDidReceiveMessage postMessage" +"GitHub Actions workflow_dispatch inputs matrix strategy" +"Aspire AddUvicornApp Python FastAPI integration" +"DevUI serve agents tracing OpenTelemetry directory discovery" +"ChatCompletionAgent plugin tool calling multi-agent orchestration" +"Agent Framework workflow conditional edges branching handoff" ``` Include context: -- **Version** when relevant (`.NET 8`, `EF Core 8`) -- **Task intent** (`quickstart`, `tutorial`, `overview`, `limits`) -- **Platform** for multi-platform docs (`Linux`, `Windows`) +- **Version** when relevant (`.NET 8`, `Aspire 13`, `VS Code 1.96`) +- **Task intent** (`quickstart`, `tutorial`, `overview`, `limits`, `API reference`) +- **Platform** for multi-platform docs (`Linux`, `Windows`, `macOS`) +- **Language** for polyglot docs (`Python`, `TypeScript`, `C#`) -## When to Fetch Full Page +### Agent Framework Query Examples -Fetch after search when: +``` +# DevUI — setup and running +microsoft_code_sample_search(language="python", query="DevUI agent framework serve agents tracing") +context7_query("/microsoft/agent-framework", "DevUI CLI options port host headless authentication") +context7_query("/websites/learn_microsoft_en-us_agent-framework", "DevUI directory discovery agent workflow __init__.py") + +# DevUI — tracing and observability +context7_query("/websites/learn_microsoft_en-us_agent-framework", "DevUI tracing OpenTelemetry debug panel span hierarchy") +microsoft_docs_search("configure tracing agent framework DevUI OTLP_ENDPOINT Jaeger") + +# DevUI — API and OpenAI SDK +context7_query("/microsoft/agent-framework", "DevUI POST /v1/responses OpenAI SDK entity_id streaming") +context7_query("/microsoft/agent-framework", "DevUI OpenAI proxy X-Proxy-Backend authentication") + +# DevUI — .NET integration +microsoft_code_sample_search(language="csharp", query="DevUI AddDevUI MapDevUI ASP.NET Core agent") +context7_query("/microsoft/agent-framework", "Microsoft.Agents.AI.DevUI AddDevUI MapDevUI ASP.NET Core") + +# Semantic Kernel agents +microsoft_code_sample_search(language="python", query="ChatCompletionAgent plugin AgentGroupChat") +context7_query("/websites/learn_microsoft_en-us_semantic-kernel", "ChatCompletionAgent plugin tool calling setup") +context7_query("/websites/learn_microsoft_en-us_semantic-kernel_frameworks_agent", "AgentGroupChat selection strategy termination") + +# Agent Framework workflows +context7_query("/websites/learn_microsoft_en-us_agent-framework", "workflow orchestration magentic handoff conditional edge") +microsoft_code_sample_search(language="csharp", query="agent framework workflow WorkflowBuilder AddEdge") + +# Cross-framework tracing +microsoft_docs_search("configure tracing AI agent frameworks Foundry Semantic Kernel Agent Framework") +``` + +## Workflow + +1. **Identify the technology** — is it Azure/Learn content, Agent Framework, Semantic Kernel, DevUI, VS Code, GitHub, or Aspire? +2. **Pick the right tool** — use the decision table above to choose between Microsoft Learn MCP and Context7 +3. **For Agent Frameworks** — use `microsoft_code_sample_search` for working code, then Context7 for deeper API docs: + - **DevUI how-to**: Context7 Learn website → code sample search for working examples → Context7 repo for API detail + - **Semantic Kernel**: Context7 Learn website + code sample search → Context7 repo for advanced samples + - **Workflow orchestration**: Microsoft Learn search → Context7 Learn website for patterns +4. **For Context7** — resolve the library ID first (if not cached), then query with a specific question +5. **For Microsoft Learn** — search first, then fetch full pages when you need complete tutorials or all config options +6. **Combine tools** — for cross-cutting questions (e.g., "deploy Aspire to Azure", "trace Agent Framework to Azure Monitor"), use multiple sources + +## When to Fetch Full Page (Microsoft Learn MCP) + +Use `microsoft_docs_fetch` after `microsoft_docs_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 +- **Agent Framework DevUI docs** — `https://learn.microsoft.com/en-us/agent-framework/user-guide/devui/` for complete setup guide ## Why Use This -- **Accuracy** — live docs, not training data that may be outdated -- **Completeness** — tutorials have all steps, not fragments -- **Authority** — official Microsoft documentation +- **Accuracy** — live docs and indexed sources, not stale training data +- **Completeness** — full tutorials, not fragments +- **Breadth** — covers the entire Microsoft ecosystem including VS Code, GitHub, Agent Framework repos, and Aspire that live outside learn.microsoft.com +- **Depth** — GitHub repo sources provide API-level detail ahead of published docs +- **Authority** — official Microsoft and first-party documentation From bdaeff279fa3072c076946d0ba83c6158434616c Mon Sep 17 00:00:00 2001 From: Chris McKee Date: Fri, 6 Feb 2026 10:09:19 -0600 Subject: [PATCH 02/17] refactor: Replace DevUI tutorial content with research guidance The skill is about how to research docs, not a DevUI tutorial. Replace the 10-step DevUI workflow checklist with a research strategy table showing which tool to use for each type of DevUI information. --- skills/microsoft-docs/SKILL.md | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/skills/microsoft-docs/SKILL.md b/skills/microsoft-docs/SKILL.md index d5511dfc..7e91ba77 100644 --- a/skills/microsoft-docs/SKILL.md +++ b/skills/microsoft-docs/SKILL.md @@ -72,25 +72,19 @@ The **Learn website** source has polished tutorials and conceptual docs. The **G **Use both** for comprehensive Agent Framework coverage: query the website source for "how to" guides, then the repo source for API-level specifics. -##### DevUI Workflow +##### Researching DevUI -DevUI is a sample app for running and debugging agents/workflows interactively. Key topics: +DevUI docs are split across Learn and the GitHub repo. The best research strategy: -1. **Installation**: `pip install agent-framework-devui --pre` -2. **Programmatic launch**: `serve(entities=[agent], auto_open=True)` — registers agents in-memory -3. **Directory discovery**: `devui ./agents --port 8080` — auto-discovers agents/workflows from `__init__.py` files -4. **Tracing**: `devui ./agents --tracing` or `serve(entities=[agent], tracing_enabled=True)` — enables OpenTelemetry traces visible in the debug panel -5. **OpenAI-compatible API**: `POST /v1/responses` with `metadata.entity_id` — use with OpenAI Python SDK -6. **OpenAI proxy**: Set `X-Proxy-Backend: openai` header to proxy requests through DevUI (keeps API key server-side) -7. **Authentication**: `devui ./agents --auth --auth-token "token"` — Bearer token auth -8. **UI modes**: `--mode developer` (default, full debug) vs `--mode user` (simplified, restricted) -9. **.NET integration**: `builder.AddDevUI()` + `app.MapDevUI()` in ASP.NET Core (development only) -10. **Export to external observability**: Set `OTLP_ENDPOINT` to send traces to Jaeger, Zipkin, Azure Monitor, Datadog +| What You Need | Where to Search | +|---------------|----------------| +| Setup tutorial, directory structure | Context7 `/websites/learn_microsoft_en-us_agent-framework` — query "DevUI directory discovery" or "DevUI tracing" | +| CLI flags, REST API endpoints, auth config | Context7 `/microsoft/agent-framework` — query "DevUI CLI options" or "DevUI POST /v1/responses" | +| Working Python code snippets | `microsoft_code_sample_search` with `language: "python"` — query "DevUI agent framework serve" | +| Working C# integration code | `microsoft_code_sample_search` with `language: "csharp"` — query "DevUI AddDevUI MapDevUI" | +| Full setup guide in one page | `microsoft_docs_fetch` with URL `https://learn.microsoft.com/en-us/agent-framework/user-guide/devui/` | -**Best query strategy for DevUI:** -- Use `microsoft_code_sample_search` with `language: "python"` for working DevUI code -- Use Context7 `/microsoft/agent-framework` for the DevUI REST API reference -- Use Context7 `/websites/learn_microsoft_en-us_agent-framework` for directory structure and tracing guides +The GitHub repo source is particularly valuable for DevUI because it contains API-level detail (endpoint schemas, proxy config, auth tokens) that the Learn page summarizes. #### Semantic Kernel From 00508b71f3612767118c240a189c7547c52ea511 Mon Sep 17 00:00:00 2001 From: Chris McKee Date: Fri, 6 Feb 2026 10:12:10 -0600 Subject: [PATCH 03/17] refactor: Remove Semantic Kernel prose, keep library reference table --- skills/microsoft-docs/SKILL.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/skills/microsoft-docs/SKILL.md b/skills/microsoft-docs/SKILL.md index 7e91ba77..1d684745 100644 --- a/skills/microsoft-docs/SKILL.md +++ b/skills/microsoft-docs/SKILL.md @@ -94,8 +94,6 @@ The GitHub repo source is particularly valuable for DevUI because it contains AP | `/websites/learn_microsoft_en-us_semantic-kernel_frameworks_agent` | 932 | 76.4 | Agent framework subset — ChatCompletionAgent, AgentGroupChat, orchestration patterns | | `/microsoft/semantic-kernel` | 2,950 | 74.7 | GitHub repo — samples, ADRs, design documents, process integration | -**Use the Learn website source** for Semantic Kernel tutorials and plugin setup. **Use the agent framework subset** for focused agent orchestration queries. **Use the GitHub repo** for sample code, architectural decisions, and advanced patterns (e.g., `GettingStartedWithProcesses`). - ### Azure & .NET (learn.microsoft.com) | Library ID | Snippets | Score | Coverage | From b5cf6a24738e93478c79f12bc706bdfce3a3b1f7 Mon Sep 17 00:00:00 2001 From: Chris McKee Date: Fri, 6 Feb 2026 10:13:28 -0600 Subject: [PATCH 04/17] refactor: Remove Semantic Kernel library reference table --- skills/microsoft-docs/SKILL.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/skills/microsoft-docs/SKILL.md b/skills/microsoft-docs/SKILL.md index 1d684745..146637c2 100644 --- a/skills/microsoft-docs/SKILL.md +++ b/skills/microsoft-docs/SKILL.md @@ -86,14 +86,6 @@ DevUI docs are split across Learn and the GitHub repo. The best research strateg The GitHub repo source is particularly valuable for DevUI because it contains API-level detail (endpoint schemas, proxy config, auth tokens) that the Learn page summarizes. -#### Semantic Kernel - -| Library ID | Snippets | Score | Coverage | -|---|---|---|---| -| `/websites/learn_microsoft_en-us_semantic-kernel` | 4,909 | 69.5 | **Primary** — agents, plugins, orchestration, function calling, migration guides | -| `/websites/learn_microsoft_en-us_semantic-kernel_frameworks_agent` | 932 | 76.4 | Agent framework subset — ChatCompletionAgent, AgentGroupChat, orchestration patterns | -| `/microsoft/semantic-kernel` | 2,950 | 74.7 | GitHub repo — samples, ADRs, design documents, process integration | - ### Azure & .NET (learn.microsoft.com) | Library ID | Snippets | Score | Coverage | From f28f8ab883c992dfa7d60cd380e8cd56c79e1038 Mon Sep 17 00:00:00 2001 From: Chris McKee Date: Fri, 6 Feb 2026 10:26:30 -0600 Subject: [PATCH 05/17] chore: Rebuild README.skills.md with updated description --- docs/README.skills.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/README.skills.md b/docs/README.skills.md index 7c3fa2e1..be0ef0a5 100644 --- a/docs/README.skills.md +++ b/docs/README.skills.md @@ -24,6 +24,7 @@ Skills differ from other primitives by supporting bundled assets (scripts, code | ---- | ----------- | -------------- | | [agentic-eval](../skills/agentic-eval/SKILL.md) | Patterns and techniques for evaluating and improving AI agent outputs. Use this skill when:
- Implementing self-critique and reflection loops
- Building evaluator-optimizer pipelines for quality-critical generation
- Creating test-driven code refinement workflows
- Designing rubric-based or LLM-as-judge evaluation systems
- Adding iterative improvement to agent outputs (code, reports, analysis)
- Measuring and improving agent response quality | None | | [appinsights-instrumentation](../skills/appinsights-instrumentation/SKILL.md) | Instrument a webapp to send useful telemetry data to Azure App Insights | `LICENSE.txt`
`examples/appinsights.bicep`
`references/ASPNETCORE.md`
`references/AUTO.md`
`references/NODEJS.md`
`references/PYTHON.md`
`scripts/appinsights.ps1` | +| [aspire](../skills/aspire/SKILL.md) | Aspire skill covering the Aspire CLI, AppHost orchestration, service discovery, integrations, MCP server, VS Code extension, Dev Containers, GitHub Codespaces, templates, dashboard, and deployment. Use when the user asks to create, run, debug, configure, deploy, or troubleshoot an Aspire distributed application. | None | | [azure-deployment-preflight](../skills/azure-deployment-preflight/SKILL.md) | Performs comprehensive preflight validation of Bicep deployments to Azure, including template syntax validation, what-if analysis, and permission checks. Use this skill before any deployment to Azure to preview changes, identify potential issues, and ensure the deployment will succeed. Activate when users mention deploying to Azure, validating Bicep files, checking deployment permissions, previewing infrastructure changes, running what-if, or preparing for azd provision. | `references/ERROR-HANDLING.md`
`references/REPORT-TEMPLATE.md`
`references/VALIDATION-COMMANDS.md` | | [azure-devops-cli](../skills/azure-devops-cli/SKILL.md) | Manage Azure DevOps resources via CLI including projects, repos, pipelines, builds, pull requests, work items, artifacts, and service endpoints. Use when working with Azure DevOps, az commands, devops automation, CI/CD, or when user mentions Azure DevOps CLI. | None | | [azure-resource-visualizer](../skills/azure-resource-visualizer/SKILL.md) | Analyze Azure resource groups and generate detailed Mermaid architecture diagrams showing the relationships between individual resources. Use this skill when the user asks for a diagram of their Azure resources or help in understanding how the resources relate to each other. | `LICENSE.txt`
`assets/template-architecture.md` | From 27c55ffdb877bdfce093631c10db681b608e734a Mon Sep 17 00:00:00 2001 From: Chris McKee <25754153+ChrisMcKee1@users.noreply.github.com> Date: Fri, 6 Feb 2026 10:32:24 -0600 Subject: [PATCH 06/17] Update skills/microsoft-docs/SKILL.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- skills/microsoft-docs/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skills/microsoft-docs/SKILL.md b/skills/microsoft-docs/SKILL.md index 146637c2..bcbb92b5 100644 --- a/skills/microsoft-docs/SKILL.md +++ b/skills/microsoft-docs/SKILL.md @@ -176,7 +176,7 @@ context7_query("/websites/learn_microsoft_en-us_semantic-kernel", "ChatCompletio context7_query("/websites/learn_microsoft_en-us_semantic-kernel_frameworks_agent", "AgentGroupChat selection strategy termination") # Agent Framework workflows -context7_query("/websites/learn_microsoft_en-us_agent-framework", "workflow orchestration magentic handoff conditional edge") +context7_query("/websites/learn_microsoft_en-us_agent-framework", "workflow orchestration multi-agent handoff conditional edge") microsoft_code_sample_search(language="csharp", query="agent framework workflow WorkflowBuilder AddEdge") # Cross-framework tracing From e4c35f3702b0c65a405c77c183107c6529658fae Mon Sep 17 00:00:00 2001 From: Chris McKee Date: Fri, 6 Feb 2026 10:36:43 -0600 Subject: [PATCH 07/17] chore: rebuild README.skills.md without aspire skill (belongs to separate PR) --- docs/README.skills.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/README.skills.md b/docs/README.skills.md index be0ef0a5..7c3fa2e1 100644 --- a/docs/README.skills.md +++ b/docs/README.skills.md @@ -24,7 +24,6 @@ Skills differ from other primitives by supporting bundled assets (scripts, code | ---- | ----------- | -------------- | | [agentic-eval](../skills/agentic-eval/SKILL.md) | Patterns and techniques for evaluating and improving AI agent outputs. Use this skill when:
- Implementing self-critique and reflection loops
- Building evaluator-optimizer pipelines for quality-critical generation
- Creating test-driven code refinement workflows
- Designing rubric-based or LLM-as-judge evaluation systems
- Adding iterative improvement to agent outputs (code, reports, analysis)
- Measuring and improving agent response quality | None | | [appinsights-instrumentation](../skills/appinsights-instrumentation/SKILL.md) | Instrument a webapp to send useful telemetry data to Azure App Insights | `LICENSE.txt`
`examples/appinsights.bicep`
`references/ASPNETCORE.md`
`references/AUTO.md`
`references/NODEJS.md`
`references/PYTHON.md`
`scripts/appinsights.ps1` | -| [aspire](../skills/aspire/SKILL.md) | Aspire skill covering the Aspire CLI, AppHost orchestration, service discovery, integrations, MCP server, VS Code extension, Dev Containers, GitHub Codespaces, templates, dashboard, and deployment. Use when the user asks to create, run, debug, configure, deploy, or troubleshoot an Aspire distributed application. | None | | [azure-deployment-preflight](../skills/azure-deployment-preflight/SKILL.md) | Performs comprehensive preflight validation of Bicep deployments to Azure, including template syntax validation, what-if analysis, and permission checks. Use this skill before any deployment to Azure to preview changes, identify potential issues, and ensure the deployment will succeed. Activate when users mention deploying to Azure, validating Bicep files, checking deployment permissions, previewing infrastructure changes, running what-if, or preparing for azd provision. | `references/ERROR-HANDLING.md`
`references/REPORT-TEMPLATE.md`
`references/VALIDATION-COMMANDS.md` | | [azure-devops-cli](../skills/azure-devops-cli/SKILL.md) | Manage Azure DevOps resources via CLI including projects, repos, pipelines, builds, pull requests, work items, artifacts, and service endpoints. Use when working with Azure DevOps, az commands, devops automation, CI/CD, or when user mentions Azure DevOps CLI. | None | | [azure-resource-visualizer](../skills/azure-resource-visualizer/SKILL.md) | Analyze Azure resource groups and generate detailed Mermaid architecture diagrams showing the relationships between individual resources. Use this skill when the user asks for a diagram of their Azure resources or help in understanding how the resources relate to each other. | `LICENSE.txt`
`assets/template-architecture.md` | From 892b265ef382003e02bb5813128f5022602e91b8 Mon Sep 17 00:00:00 2001 From: Michael Fairchild Date: Fri, 6 Feb 2026 14:44:13 -0600 Subject: [PATCH 08/17] Revise accessibility instructions for clarity and detail Updated accessibility instructions to improve clarity and specificity regarding coding practices for accessibility, including keyboard navigation and semantic structure. --- instructions/a11y.instructions.md | 487 +++++++++++++----------------- 1 file changed, 210 insertions(+), 277 deletions(-) diff --git a/instructions/a11y.instructions.md b/instructions/a11y.instructions.md index 78b3908e..d80a6ee5 100644 --- a/instructions/a11y.instructions.md +++ b/instructions/a11y.instructions.md @@ -3,75 +3,77 @@ description: "Guidance for creating more accessible code" 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/). -2. Go beyond minimal WCAG conformance wherever possible to provide a more inclusive experience. -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. -4. After generating code, review it against WCAG 2.2 and these instructions. Iterate on the code until it is accessible. -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. +- Conform to [WCAG 2.2 Level AA](https://www.w3.org/TR/WCAG22/). +- Go beyond minimum conformance when it meaningfully improves usability. +- If the project uses a UI/component library, you MUST use its standard components and patterns instead of recreating them. + - Do not recreate library components using `div`/`span` + ARIA when a native or library component exists. + - 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** - 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. +## Cognitive load (SHOULD) -- **Bias-Aware and Error-Resistant** - 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. +- Prefer plain language. +- Use consistent page structure (landmarks). +- Keep navigation order consistent. +- Keep the interface clean and simple (avoid unnecessary distractions). -- **Verification-Oriented Responses** - 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. +## Structure and semantics -- **Clarity Without Oversimplification** - Provide concise but accurate explanations—avoid fluff, empty reassurance, or overconfidence when accessibility nuances are present. +### Page structure (MUST) -- **Tone Matters** - Copilot output must be neutral, helpful, and respectful. Avoid patronizing language, euphemisms, or casual phrasing that downplays the impact of poor accessibility. +- Use landmarks (`header`, `nav`, `main`, `footer`) appropriately. +- Use headings to introduce sections; avoid skipping heading levels. +- Prefer one `h1` for the page topic. -## Persona based instructions +### Page title (SHOULD) -### Cognitive instructions +- Set a descriptive ``. +- Prefer: “Unique page - section - site”. -- Prefer plain language whenever possible. -- 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 and focus -### 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). -- Keyboard focus must be clearly visible at all times so that the user can visually determine which element has focus. -- 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. -- Static (non-interactive) elements, should not be in the tab order. These elements should not have a `tabindex` attribute. - - 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. -- Hidden elements must not be keyboard focusable. -- 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: - - 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). +- All interactive elements are keyboard operable. +- Tab order follows reading order and is predictable. +- Focus is always visible. +- Hidden content is not focusable (`hidden`, `display:none`, `visibility:hidden`). +- Static content MUST NOT be tabbable. + - Exception: if an element needs programmatic focus, use `tabindex="-1"`. +- Focus MUST NOT be trapped. -#### 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 <header> - <a href="#maincontent" class="sr-only">Skip to main</a> - <!-- logo and other header elements here --> + <a href="#maincontent" class="sr-only">Skip to main content</a> + <!-- header content --> </header> <nav> - <!-- main nav here --> + <!-- navigation --> </nav> -<main id="maincontent"></main> +<main id="maincontent" tabindex="-1"> + <h1><!-- page title --></h1> + <!-- content --> +</main> ``` ```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. -- `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. +If a component uses arrow-key navigation within itself (tabs, listbox, menu-like UI, grid/date picker): -#### 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. -- When the component contains focus and the user presses an arrow key that moves focus within the component: - - 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"`. +- Exactly one focusable item has `tabindex="0"`; all others are `-1`. +- Arrow keys move focus by swapping tabindex and calling `.focus()`. -#### 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. -- Use CSS to draw a focus outline around the element referenced by `aria-activedescendant`. -- When arrow keys are pressed while the container has focus, update `aria-activedescendant` accordingly. +- Container has `tabindex="0"` and `aria-activedescendant="IDREF"`. +- Arrow keys update `aria-activedescendant`. -### Low vision instructions +## Low vision and contrast (MUST) -- Prefer dark text on light backgrounds, or light text on dark backgrounds. -- 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. +### Contrast requirements (MUST) -### 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. -- 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. +### Color generation rules (MUST) -### 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. -- Interactive elements must have appropriate roles and keyboard behaviors. +### Safe defaults when unsure (SHOULD) -## 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. -- Headings must accurately describe the topic that they introduce. -- 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()`. +- Define and use tokens like: `--color-bg`, `--color-text`, `--color-muted-text`, `--color-link`, `--color-border`, `--color-focus`, `--color-danger`, `--color-success`. +- Only assign UI colors via these tokens (avoid scattered inline hex values). -### 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. -- `<svg>` elements. -- Font icons -- Emojis +### Support OS-level accessibility features (MUST) -#### 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. -- 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. +Use `@media (forced-colors: active)` only when system defaults are not sufficient. -#### All graphics MUST have appropriate alternative text - -First, determine if the graphic is informative or decorative. - -- Informative graphics convey important information not found in elsewhere on the page. -- 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> +```css +@media (forced-colors: active) { + /* Example: Replace box-shadow (suppressed in forced-colors) with a border */ + .button { + border: 2px solid ButtonBorder; + } +} ``` -#### Navigation instructions +In Forced Colors mode, avoid relying on: -- Follow the above code example where possible. -- 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. -- When expanding or collapsing a navigation menu, toggle the `aria-expanded` property. -- 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. +- Box shadows +- Background images +- Decorative gradients -### 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>`. -- 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]" +### Do not disable forced colors (MUST) -### 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: - -```html -<table> - <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> +```css +svg { + fill: currentColor; + stroke: currentColor; +} ``` -#### Good example - table with just column headers: +## Reflow (WCAG 2.2 SC 1.4.10) (MUST) -```html -<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> -``` +### Goal (MUST) -#### 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 -<div role="grid"> - <div role="columnheader">Sun</div> - <div role="columnheader">Mon</div> - <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> -``` +- Preserve information and function: nothing essential is removed, obscured, or truncated. +- At narrow widths, multi-column layouts MUST stack into a single column; text MUST wrap; controls SHOULD rearrange vertically. +- Users SHOULD NOT need to scroll left/right to read multi-line text. +- If content is collapsed in the narrow layout, the full content/function MUST be available within 1 click (e.g., overflow menu, dialog, tooltip). -##### The good: +### Engineering requirements (MUST) -- It uses `role="grid"` to indicate that it is a grid. -- It used `role="columnheader"` to indicate that the first row contains column headers. -- 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. +- Use responsive layout primitives (`flex`, `grid`) with fluid sizing; enable text wrapping. +- Avoid fixed widths that force horizontal scrolling at 320px. +- 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. From 3024e9d6ecc1cb6c86c8dfba92a389f9e9fd7fc0 Mon Sep 17 00:00:00 2001 From: Michael Fairchild <mfairchild365@proton.me> Date: Fri, 6 Feb 2026 15:12:47 -0600 Subject: [PATCH 09/17] Update instructions/a11y.instructions.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- instructions/a11y.instructions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instructions/a11y.instructions.md b/instructions/a11y.instructions.md index d80a6ee5..91a5bc02 100644 --- a/instructions/a11y.instructions.md +++ b/instructions/a11y.instructions.md @@ -39,7 +39,7 @@ You are an expert in accessibility with deep software engineering expertise. - Use landmarks (`header`, `nav`, `main`, `footer`) appropriately. - Use headings to introduce sections; avoid skipping heading levels. -- Prefer one `h1` for the page topic. +- Use exactly one `h1` for the page topic. ### Page title (SHOULD) From ae7bb2aa7ca2fd3ffbfcab434c63f860e6f9d8e1 Mon Sep 17 00:00:00 2001 From: Chris McKee <chrismckee@microsoft.com> Date: Sun, 8 Feb 2026 20:22:52 -0600 Subject: [PATCH 10/17] refactor: Simplify microsoft-docs skill to default-Learn-with-exceptions pattern, add Aspire MCP version gate --- docs/README.skills.md | 2 +- skills/microsoft-docs/SKILL.md | 212 +++++++++------------------------ 2 files changed, 57 insertions(+), 157 deletions(-) diff --git a/docs/README.skills.md b/docs/README.skills.md index 7c3fa2e1..8e7cebfd 100644 --- a/docs/README.skills.md +++ b/docs/README.skills.md @@ -43,7 +43,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 | | [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-docs](../skills/microsoft-docs/SKILL.md) | Query official Microsoft and Microsoft-adjacent documentation to understand concepts, find tutorials, and get code examples. Covers Azure, .NET, Agent Framework, Semantic Kernel, DevUI, Aspire, VS Code, GitHub, Microsoft 365, Windows, and Power Platform using Microsoft Learn MCP and Context7 for comprehensive lookup across learn.microsoft.com, code.visualstudio.com, docs.github.com, aspire.dev, and GitHub source repos. | 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 | | [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` | | [plantuml-ascii](../skills/plantuml-ascii/SKILL.md) | Generate ASCII art diagrams using PlantUML text mode. Use when user asks to create ASCII diagrams, text-based diagrams, terminal-friendly diagrams, or mentions plantuml ascii, text diagram, ascii art diagram. Supports: Converting PlantUML diagrams to ASCII art, Creating sequence diagrams, class diagrams, flowcharts in ASCII format, Generating Unicode-enhanced ASCII art with -utxt flag | None | diff --git a/skills/microsoft-docs/SKILL.md b/skills/microsoft-docs/SKILL.md index bcbb92b5..201b5e00 100644 --- a/skills/microsoft-docs/SKILL.md +++ b/skills/microsoft-docs/SKILL.md @@ -1,213 +1,113 @@ --- name: microsoft-docs -description: 'Query official Microsoft and Microsoft-adjacent documentation to understand concepts, find tutorials, and get code examples. Covers Azure, .NET, Agent Framework, Semantic Kernel, DevUI, Aspire, VS Code, GitHub, Microsoft 365, Windows, and Power Platform using Microsoft Learn MCP and Context7 for comprehensive lookup across learn.microsoft.com, code.visualstudio.com, docs.github.com, aspire.dev, and GitHub source repos.' +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.' --- # Microsoft Docs -A unified documentation research skill for the full Microsoft technology ecosystem — including technologies like VS Code, GitHub, and Agent Framework repos that live outside or ahead of learn.microsoft.com. +Research skill for the Microsoft technology ecosystem. Covers learn.microsoft.com and documentation that lives outside it (VS Code, GitHub, Aspire, Agent Framework repos). -## Tools +--- -### Microsoft Learn MCP Server +## Default: Microsoft Learn MCP -| Tool | Use For | +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 on learn.microsoft.com — concepts, guides, tutorials, configuration | -| `microsoft_code_sample_search` | Find **working code snippets** from official Microsoft Learn docs. Especially strong for Agent Framework, Semantic Kernel, DevUI, and Azure SDK examples. Pass `language` parameter (`python`, `csharp`) for best results. | -| `microsoft_docs_fetch` | Get full page content from a specific Microsoft docs URL (when search excerpts aren't enough) | +| `microsoft_docs_search` | Search learn.microsoft.com — concepts, guides, tutorials, configuration | +| `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) | -### Context7 (broader coverage) +Use `microsoft_docs_fetch` after search when you need complete tutorials, all config options, or when search excerpts are truncated. -Context7 indexes both **websites** and **GitHub repos**, giving access to documentation that the Microsoft Learn MCP server cannot reach — including VS Code docs, GitHub docs, Aspire.dev, GitHub CLI, and README-level content from source repos that is often ahead of published docs. +--- -| Tool | Use For | -|------|---------| -| `mcp_context7_resolve-library-id` | Find the Context7 library ID for a technology (one-time per session) | -| `mcp_context7_query-docs` | Query docs with a specific library ID — returns code snippets, explanations, and source links in a single call | +## Exceptions: When to Use Other Tools -### When GitHub Repo Sources (Context7) Beat Published Docs +The following categories live **outside** learn.microsoft.com. Use the specified tool instead. -Context7 indexes GitHub repo README files, which often contain API-level detail, CLI references, and advanced config that hasn't been published to learn.microsoft.com yet. This is especially true for: +### .NET Aspire — Use Aspire MCP Server (preferred) or Context7 -- **DevUI** — the repo README (`/microsoft/agent-framework`) has complete API reference (endpoints, parameters, response schemas), OpenAI proxy config, and auth setup that the Learn page summarizes -- **Agent Framework .NET** — the repo has `Microsoft.Agents.AI.DevUI` integration code for ASP.NET Core before it appears on Learn -- **Extension samples** — `/microsoft/vscode-extension-samples` has working projects not always linked from the VS Code API docs +Aspire docs live on **aspire.dev**, not Learn. The best tool depends on your Aspire CLI version: -**Rule of thumb:** query the **website source** for tutorials and concepts, then the **repo source** for API-level detail and the latest features. +**CLI 13.2+** (recommended) — The Aspire MCP server includes built-in docs search tools: -## When to Use Which Tool +| 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 | -| Scenario | Best Tool | Why | -|----------|-----------|-----| -| Azure services, .NET, M365, Power Platform | `microsoft_docs_search` | Direct access to learn.microsoft.com | -| Code samples for any Learn topic | `microsoft_code_sample_search` | Returns up to 20 working code snippets with links. Filter by language. | -| Agent Framework — tutorials, concepts | `microsoft_docs_search` + Context7 Learn | Polished guides on learn.microsoft.com | -| Agent Framework — DevUI setup, API, CLI | Context7 `/microsoft/agent-framework` | GitHub repo has detailed DevUI README with full API reference | -| Agent Framework — DevUI tracing, directory discovery | Context7 `/websites/learn_microsoft_en-us_agent-framework` | Learn website has step-by-step guides | -| Semantic Kernel — agents, plugins, orchestration | Context7 `/websites/learn_microsoft_en-us_semantic-kernel` + `microsoft_code_sample_search` | Learn has the best SK docs; code sample search excels here | -| Semantic Kernel — source code, ADRs, design docs | Context7 `/microsoft/semantic-kernel` | GitHub repo has samples and architectural decisions | -| VS Code features, settings, shortcuts | Context7 `/websites/code_visualstudio` | VS Code docs live on code.visualstudio.com, not Learn | -| VS Code extension development / API | Context7 `/websites/code_visualstudio_api` | Extension API docs are separate from user docs | -| GitHub Actions, repos, API, features | Context7 `/websites/github_en` | GitHub docs live on docs.github.com | -| GitHub CLI (gh) | Context7 `/websites/cli_github` | CLI reference lives on cli.github.com | -| .NET Aspire (AppHost, integrations, CLI) | Context7 `/microsoft/aspire.dev` | Aspire docs live on aspire.dev, not Learn | -| Aspire community integrations (Go, Java) | Context7 `/communitytoolkit/aspire` | Community Toolkit is a separate repo | -| Need full tutorial with all steps | `microsoft_docs_fetch` | Gets complete page content | +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/ -## Context7 Library Reference +**CLI 13.1** — The MCP server provides integration lookup (`list_integrations`, `get_integration_docs`) but **not** docs search. Fall back to Context7: -Call `mcp_context7_resolve-library-id` once per session to confirm IDs. Below are tested, quality-ranked sources. +| 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 | -### Agent Frameworks +### VS Code — Use Context7 -#### Microsoft Agent Framework +VS Code docs live on **code.visualstudio.com**, not Learn. -| Library ID | Snippets | Score | Coverage | -|---|---|---|---| -| `/websites/learn_microsoft_en-us_agent-framework` | 2,282 | 81.2 | **Primary for tutorials** — DevUI guides, directory discovery, tracing, AG-UI integration, workflow orchestration | -| `/microsoft/agent-framework` | 1,177 | — | **Primary for API detail** — DevUI README (full REST API, CLI flags, auth, OpenAI proxy), .NET DevUI integration, samples | +| 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 | -The **Learn website** source has polished tutorials and conceptual docs. The **GitHub repo** source has README-level detail that is often ahead of published docs — particularly the DevUI REST API reference, advanced CLI options, and .NET `Microsoft.Agents.AI.DevUI` package setup. +### GitHub — Use Context7 -**Use both** for comprehensive Agent Framework coverage: query the website source for "how to" guides, then the repo source for API-level specifics. +GitHub docs live on **docs.github.com** and **cli.github.com**. -##### Researching DevUI +| Library ID | Use for | +|---|---| +| `/websites/github_en` | Actions, API, repos, security, admin, Copilot | +| `/websites/cli_github` | GitHub CLI (`gh`) commands and flags | -DevUI docs are split across Learn and the GitHub repo. The best research strategy: +### Agent Framework — Use Learn MCP + Context7 -| What You Need | Where to Search | -|---------------|----------------| -| Setup tutorial, directory structure | Context7 `/websites/learn_microsoft_en-us_agent-framework` — query "DevUI directory discovery" or "DevUI tracing" | -| CLI flags, REST API endpoints, auth config | Context7 `/microsoft/agent-framework` — query "DevUI CLI options" or "DevUI POST /v1/responses" | -| Working Python code snippets | `microsoft_code_sample_search` with `language: "python"` — query "DevUI agent framework serve" | -| Working C# integration code | `microsoft_code_sample_search` with `language: "csharp"` — query "DevUI AddDevUI MapDevUI" | -| Full setup guide in one page | `microsoft_docs_fetch` with URL `https://learn.microsoft.com/en-us/agent-framework/user-guide/devui/` | +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. -The GitHub repo source is particularly valuable for DevUI because it contains API-level detail (endpoint schemas, proxy config, auth tokens) that the Learn page summarizes. +| 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` | -### Azure & .NET (learn.microsoft.com) +**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). -| Library ID | Snippets | Score | Coverage | -|---|---|---|---| -| `/websites/learn_microsoft_en-us_azure` | 164,912 | 73.8 | All Azure services — compute, storage, networking, AI, databases | -| `/microsoftdocs/azure-docs` | 61,791 | 76.7 | Azure docs GitHub repo — higher quality score | -| `/websites/learn_microsoft_en-us` | 158,360 | 45.4 | All of Microsoft Learn — broadest but lower precision | -| `/websites/learn_microsoft_en-us_dotnet_azure` | 1,156 | — | Azure SDK for .NET developers specifically | +--- -### .NET Aspire +## Context7 Setup -| Library ID | Snippets | Score | Coverage | -|---|---|---|---| -| `/microsoft/aspire.dev` | 1,865 | 73.0 | **Primary** — official docs site repo, best quality, full Aspire 13+ coverage | -| `/websites/aspire_dev` | 31,845 | 71.6 | Website crawl — massive but includes multilingual duplicates | -| `/dotnet/aspire` | 1,185 | 71.5 | Runtime source — API internals, playground examples | -| `/communitytoolkit/aspire` | 311 | 64.2 | Community integrations — Golang, Java, Node.js, Vite, Ollama | -| `/dotnet/docs-aspire` | 482 | 71.4 | **Legacy** — being superseded by aspire.dev, avoid for tutorials | +For any Context7 query, resolve the library ID first (one-time per session): -### Visual Studio Code +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 -| Library ID | Snippets | Score | Coverage | -|---|---|---|---| -| `/websites/code_visualstudio` | 6,288 | 80.4 | **Primary** — user docs, settings, features, debugging, remote dev | -| `/websites/code_visualstudio_api` | 1,681 | 65.4 | Extension API — webviews, TreeViews, commands, contribution points | -| `/microsoft/vscode-docs` | 8,289 | 87.9 | Docs repo — highest score, markdown source files | -| `/microsoft/vscode-extension-samples` | 320 | 82.4 | Extension samples — working code examples | +--- -### GitHub +## Writing Effective Queries -| Library ID | Snippets | Score | Coverage | -|---|---|---|---| -| `/websites/github_en` | 43,828 | 66.2 | **Primary** — Actions, API, repos, security, admin, Copilot | -| `/github/docs` | 24,544 | 73.7 | Docs repo — markdown source, higher quality score | -| `/websites/cli_github` | 386 | 83.2 | GitHub CLI reference — gh commands, flags, examples | -| `/websites/cli_github_manual` | 478 | 44.0 | CLI manual — alternative, lower score | - -## Query Effectiveness - -Good queries are specific: +Be specific — include version, intent, and language: ``` # ❌ Too broad "Azure Functions" -"VS Code extensions" "agent framework" # ✅ Specific "Azure Functions Python v2 programming model" "Cosmos DB partition key design best practices" -"VS Code webview API onDidReceiveMessage postMessage" "GitHub Actions workflow_dispatch inputs matrix strategy" "Aspire AddUvicornApp Python FastAPI integration" "DevUI serve agents tracing OpenTelemetry directory discovery" -"ChatCompletionAgent plugin tool calling multi-agent orchestration" "Agent Framework workflow conditional edges branching handoff" ``` Include context: - **Version** when relevant (`.NET 8`, `Aspire 13`, `VS Code 1.96`) - **Task intent** (`quickstart`, `tutorial`, `overview`, `limits`, `API reference`) -- **Platform** for multi-platform docs (`Linux`, `Windows`, `macOS`) - **Language** for polyglot docs (`Python`, `TypeScript`, `C#`) - -### Agent Framework Query Examples - -``` -# DevUI — setup and running -microsoft_code_sample_search(language="python", query="DevUI agent framework serve agents tracing") -context7_query("/microsoft/agent-framework", "DevUI CLI options port host headless authentication") -context7_query("/websites/learn_microsoft_en-us_agent-framework", "DevUI directory discovery agent workflow __init__.py") - -# DevUI — tracing and observability -context7_query("/websites/learn_microsoft_en-us_agent-framework", "DevUI tracing OpenTelemetry debug panel span hierarchy") -microsoft_docs_search("configure tracing agent framework DevUI OTLP_ENDPOINT Jaeger") - -# DevUI — API and OpenAI SDK -context7_query("/microsoft/agent-framework", "DevUI POST /v1/responses OpenAI SDK entity_id streaming") -context7_query("/microsoft/agent-framework", "DevUI OpenAI proxy X-Proxy-Backend authentication") - -# DevUI — .NET integration -microsoft_code_sample_search(language="csharp", query="DevUI AddDevUI MapDevUI ASP.NET Core agent") -context7_query("/microsoft/agent-framework", "Microsoft.Agents.AI.DevUI AddDevUI MapDevUI ASP.NET Core") - -# Semantic Kernel agents -microsoft_code_sample_search(language="python", query="ChatCompletionAgent plugin AgentGroupChat") -context7_query("/websites/learn_microsoft_en-us_semantic-kernel", "ChatCompletionAgent plugin tool calling setup") -context7_query("/websites/learn_microsoft_en-us_semantic-kernel_frameworks_agent", "AgentGroupChat selection strategy termination") - -# Agent Framework workflows -context7_query("/websites/learn_microsoft_en-us_agent-framework", "workflow orchestration multi-agent handoff conditional edge") -microsoft_code_sample_search(language="csharp", query="agent framework workflow WorkflowBuilder AddEdge") - -# Cross-framework tracing -microsoft_docs_search("configure tracing AI agent frameworks Foundry Semantic Kernel Agent Framework") -``` - -## Workflow - -1. **Identify the technology** — is it Azure/Learn content, Agent Framework, Semantic Kernel, DevUI, VS Code, GitHub, or Aspire? -2. **Pick the right tool** — use the decision table above to choose between Microsoft Learn MCP and Context7 -3. **For Agent Frameworks** — use `microsoft_code_sample_search` for working code, then Context7 for deeper API docs: - - **DevUI how-to**: Context7 Learn website → code sample search for working examples → Context7 repo for API detail - - **Semantic Kernel**: Context7 Learn website + code sample search → Context7 repo for advanced samples - - **Workflow orchestration**: Microsoft Learn search → Context7 Learn website for patterns -4. **For Context7** — resolve the library ID first (if not cached), then query with a specific question -5. **For Microsoft Learn** — search first, then fetch full pages when you need complete tutorials or all config options -6. **Combine tools** — for cross-cutting questions (e.g., "deploy Aspire to Azure", "trace Agent Framework to Azure Monitor"), use multiple sources - -## When to Fetch Full Page (Microsoft Learn MCP) - -Use `microsoft_docs_fetch` after `microsoft_docs_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 -- **Agent Framework DevUI docs** — `https://learn.microsoft.com/en-us/agent-framework/user-guide/devui/` for complete setup guide - -## Why Use This - -- **Accuracy** — live docs and indexed sources, not stale training data -- **Completeness** — full tutorials, not fragments -- **Breadth** — covers the entire Microsoft ecosystem including VS Code, GitHub, Agent Framework repos, and Aspire that live outside learn.microsoft.com -- **Depth** — GitHub repo sources provide API-level detail ahead of published docs -- **Authority** — official Microsoft and first-party documentation From e9a7805e2b1dbda5ad4d0cc9be1fc3ef6273e115 Mon Sep 17 00:00:00 2001 From: Joseph Van der Wee <jvanderwee@users.noreply.github.com> Date: Mon, 9 Feb 2026 09:06:56 +0000 Subject: [PATCH 11/17] Fix `gh pr review` body flag See https://cli.github.com/manual/gh_pr_review --- skills/gh-cli/SKILL.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/skills/gh-cli/SKILL.md b/skills/gh-cli/SKILL.md index c0d7f5ee..6756f0b5 100644 --- a/skills/gh-cli/SKILL.md +++ b/skills/gh-cli/SKILL.md @@ -1148,8 +1148,7 @@ gh pr comment 123 --delete 456789 gh pr review 123 # Approve PR -gh pr review 123 --approve \ - --approve-body "LGTM!" +gh pr review 123 --approve --body "LGTM!" # Request changes gh pr review 123 --request-changes \ From 3274ad6c684d9e673e0fc52b63d545c962b0279a Mon Sep 17 00:00:00 2001 From: Michael Fairchild <mfairchild365@proton.me> Date: Mon, 9 Feb 2026 09:40:33 -0600 Subject: [PATCH 12/17] Update readme --- collections/security-best-practices.md | 2 +- docs/README.instructions.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/collections/security-best-practices.md b/collections/security-best-practices.md index 72b9dd5e..5e68dbd5 100644 --- a/collections/security-best-practices.md +++ b/collections/security-best-practices.md @@ -8,8 +8,8 @@ Security frameworks, accessibility guidelines, performance optimization, and cod | Title | Type | Description | | ----- | ---- | ----------- | +| [Accessibility instructions](../instructions/a11y.instructions.md)<br />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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. | diff --git a/docs/README.instructions.md b/docs/README.instructions.md index 8e21748e..305e8b77 100644 --- a/docs/README.instructions.md +++ b/docs/README.instructions.md @@ -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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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. | From 0af1852dd2a699925634741b6c2adbc84bb75444 Mon Sep 17 00:00:00 2001 From: Roberto Perez <roberto@robertoperez.me> Date: Mon, 9 Feb 2026 16:42:28 -0500 Subject: [PATCH 13/17] Add VS Code Insiders Accessibility Tracker agent --- agents/insiders-a11y-tracker.agent.md | 52 +++++++++++++++++++++++++++ docs/README.agents.md | 1 + 2 files changed, 53 insertions(+) create mode 100644 agents/insiders-a11y-tracker.agent.md diff --git a/agents/insiders-a11y-tracker.agent.md b/agents/insiders-a11y-tracker.agent.md new file mode 100644 index 00000000..d033ba3e --- /dev/null +++ b/agents/insiders-a11y-tracker.agent.md @@ -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. \ No newline at end of file diff --git a/docs/README.agents.md b/docs/README.agents.md index 829eaa06..53768b3f 100644 --- a/docs/README.agents.md +++ b/docs/README.agents.md @@ -160,6 +160,7 @@ Custom agents for GitHub Copilot, making it easy for users and organizations to | [Universal Janitor](../agents/janitor.agent.md)<br />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](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 />[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](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. | | From 27149859a410d88a5116454feaa758aef06a2da5 Mon Sep 17 00:00:00 2001 From: jhauga <johnhaugabook@gmail.com> Date: Mon, 9 Feb 2026 19:21:11 -0500 Subject: [PATCH 14/17] Add skill to create web forms Add skill to create web forms --- docs/README.skills.md | 1 + skills/create-web-form/SKILL.md | 87 + .../references/accessibility.md | 512 ++++ .../references/aria-form-role.md | 156 ++ .../create-web-form/references/css-styling.md | 1027 +++++++ .../create-web-form/references/form-basics.md | 451 +++ .../references/form-controls.md | 851 ++++++ .../references/form-data-handling.md | 627 +++++ .../references/html-form-elements.md | 822 ++++++ .../references/html-form-example.md | 990 +++++++ .../references/hypertext-transfer-protocol.md | 1227 +++++++++ .../create-web-form/references/javascript.md | 2413 +++++++++++++++++ .../create-web-form/references/php-cookies.md | 145 + .../create-web-form/references/php-forms.md | 601 ++++ skills/create-web-form/references/php-json.md | 202 ++ .../references/php-mysql-database.md | 1696 ++++++++++++ .../references/progressive-web-app.md | 211 ++ .../references/python-as-web-framework.md | 567 ++++ .../references/python-contact-form.md | 453 ++++ .../references/python-flask-app.md | 449 +++ .../references/python-flask.md | 432 +++ skills/create-web-form/references/security.md | 136 + .../references/styling-web-forms.md | 1643 +++++++++++ skills/create-web-form/references/web-api.md | 165 ++ .../references/web-performance.md | 974 +++++++ skills/create-web-form/references/xml.md | 366 +++ 26 files changed, 17204 insertions(+) create mode 100644 skills/create-web-form/SKILL.md create mode 100644 skills/create-web-form/references/accessibility.md create mode 100644 skills/create-web-form/references/aria-form-role.md create mode 100644 skills/create-web-form/references/css-styling.md create mode 100644 skills/create-web-form/references/form-basics.md create mode 100644 skills/create-web-form/references/form-controls.md create mode 100644 skills/create-web-form/references/form-data-handling.md create mode 100644 skills/create-web-form/references/html-form-elements.md create mode 100644 skills/create-web-form/references/html-form-example.md create mode 100644 skills/create-web-form/references/hypertext-transfer-protocol.md create mode 100644 skills/create-web-form/references/javascript.md create mode 100644 skills/create-web-form/references/php-cookies.md create mode 100644 skills/create-web-form/references/php-forms.md create mode 100644 skills/create-web-form/references/php-json.md create mode 100644 skills/create-web-form/references/php-mysql-database.md create mode 100644 skills/create-web-form/references/progressive-web-app.md create mode 100644 skills/create-web-form/references/python-as-web-framework.md create mode 100644 skills/create-web-form/references/python-contact-form.md create mode 100644 skills/create-web-form/references/python-flask-app.md create mode 100644 skills/create-web-form/references/python-flask.md create mode 100644 skills/create-web-form/references/security.md create mode 100644 skills/create-web-form/references/styling-web-forms.md create mode 100644 skills/create-web-form/references/web-api.md create mode 100644 skills/create-web-form/references/web-performance.md create mode 100644 skills/create-web-form/references/xml.md diff --git a/docs/README.skills.md b/docs/README.skills.md index c2c3090f..5eefcc81 100644 --- a/docs/README.skills.md +++ b/docs/README.skills.md @@ -31,6 +31,7 @@ Skills differ from other primitives by supporting bundled assets (scripts, code | [azure-static-web-apps](../skills/azure-static-web-apps/SKILL.md) | Helps create, configure, and deploy Azure Static Web Apps using the SWA CLI. Use when deploying static sites to Azure, setting up SWA local development, configuring staticwebapp.config.json, adding Azure Functions APIs to SWA, or setting up GitHub Actions CI/CD for Static Web Apps. | None | | [chrome-devtools](../skills/chrome-devtools/SKILL.md) | Expert-level browser automation, debugging, and performance analysis using Chrome DevTools MCP. Use for interacting with web pages, capturing screenshots, analyzing network traffic, and profiling performance. | None | | [copilot-sdk](../skills/copilot-sdk/SKILL.md) | Build agentic applications with GitHub Copilot SDK. Use when embedding AI agents in apps, creating custom tools, implementing streaming responses, managing sessions, connecting to MCP servers, or creating custom agents. Triggers on Copilot SDK, GitHub SDK, agentic app, embed Copilot, programmable agent, MCP server, custom agent. | None | +| [create-web-form](../skills/create-web-form/SKILL.md) | Create robust, accessible web forms with best practices for HTML structure, CSS styling, JavaScript interactivity, form validation, and server-side processing. Use when asked to "create a form", "build a web form", "add a contact form", "make a signup form", or when building any HTML form with data handling. Covers PHP and Python backends, MySQL database integration, REST APIs, XML data exchange, accessibility (ARIA), and progressive web apps. | `references/accessibility.md`<br />`references/aria-form-role.md`<br />`references/css-styling.md`<br />`references/form-basics.md`<br />`references/form-controls.md`<br />`references/form-data-handling.md`<br />`references/html-form-elements.md`<br />`references/html-form-example.md`<br />`references/hypertext-transfer-protocol.md`<br />`references/javascript.md`<br />`references/php-cookies.md`<br />`references/php-forms.md`<br />`references/php-json.md`<br />`references/php-mysql-database.md`<br />`references/progressive-web-app.md`<br />`references/python-as-web-framework.md`<br />`references/python-contact-form.md`<br />`references/python-flask-app.md`<br />`references/python-flask.md`<br />`references/security.md`<br />`references/styling-web-forms.md`<br />`references/web-api.md`<br />`references/web-performance.md`<br />`references/xml.md` | | [excalidraw-diagram-generator](../skills/excalidraw-diagram-generator/SKILL.md) | Generate Excalidraw diagrams from natural language descriptions. Use when asked to "create a diagram", "make a flowchart", "visualize a process", "draw a system architecture", "create a mind map", or "generate an Excalidraw file". Supports flowcharts, relationship diagrams, mind maps, and system architecture diagrams. Outputs .excalidraw JSON files that can be opened directly in Excalidraw. | `references/element-types.md`<br />`references/excalidraw-schema.md`<br />`scripts/.gitignore`<br />`scripts/README.md`<br />`scripts/add-arrow.py`<br />`scripts/add-icon-to-diagram.py`<br />`scripts/split-excalidraw-library.py`<br />`templates/business-flow-swimlane-template.excalidraw`<br />`templates/class-diagram-template.excalidraw`<br />`templates/data-flow-diagram-template.excalidraw`<br />`templates/er-diagram-template.excalidraw`<br />`templates/flowchart-template.excalidraw`<br />`templates/mindmap-template.excalidraw`<br />`templates/relationship-template.excalidraw`<br />`templates/sequence-diagram-template.excalidraw` | | [gh-cli](../skills/gh-cli/SKILL.md) | GitHub CLI (gh) comprehensive reference for repositories, issues, pull requests, Actions, projects, releases, gists, codespaces, organizations, extensions, and all GitHub operations from the command line. | None | | [git-commit](../skills/git-commit/SKILL.md) | Execute git commit with conventional commit message analysis, intelligent staging, and message generation. Use when user asks to commit changes, create a git commit, or mentions "/commit". Supports: (1) Auto-detecting type and scope from changes, (2) Generating conventional commit messages from diff, (3) Interactive commit with optional type/scope/description overrides, (4) Intelligent file staging for logical grouping | None | diff --git a/skills/create-web-form/SKILL.md b/skills/create-web-form/SKILL.md new file mode 100644 index 00000000..62017f83 --- /dev/null +++ b/skills/create-web-form/SKILL.md @@ -0,0 +1,87 @@ +--- +name: create-web-form +description: 'Create robust, accessible web forms with best practices for HTML structure, CSS styling, JavaScript interactivity, form validation, and server-side processing. Use when asked to "create a form", "build a web form", "add a contact form", "make a signup form", or when building any HTML form with data handling. Covers PHP and Python backends, MySQL database integration, REST APIs, XML data exchange, accessibility (ARIA), and progressive web apps.' +--- + +# Create Web Form Skill + +## Overview + +This skill provides comprehensive reference materials and best practices for creating web forms. It covers HTML syntax, UI/UX design, form validation, server-side processing (PHP and Python), data handling, and network communication. + +## Purpose + +Enable developers to build robust, accessible, and user-friendly web forms by providing: + +- HTML form syntax and structure +- CSS styling techniques for form elements +- JavaScript for form interactivity and validation +- Accessibility best practices +- Server-side form processing with PHP and Python +- Database integration methods +- Network data handling and security +- Performance optimization + +## Reference Files + +This skill includes the following reference documentation: + +### UI & Styling +- `styling-web-forms.md` - Form styling techniques and best practices +- `css-styling.md` - Comprehensive CSS reference for form styling + +### User Experience +- `accessibility.md` - Web accessibility guidelines for forms +- `javascript.md` - JavaScript techniques for form functionality +- `form-controls.md` - Native form controls and their usage +- `progressive-web-app.md` - Progressive web app integration + +### HTML Structure +- `form-basics.md` - Fundamental HTML form structure +- `aria-form-role.md` - ARIA roles for accessible forms +- `html-form-elements.md` - Complete HTML form elements reference +- `html-form-example.md` - Practical HTML form examples +- `html-reference.md` - General HTML reference + +### Server-Side Processing +- `form-data-handling.md` - Network form data handling +- `php-forms.md` - PHP form processing +- `php-cookies.md` - Cookie management in PHP +- `php-json.md` - JSON handling in PHP +- `php-mysql-database.md` - Database integration with PHP +- `php-reference.md` - PHP language reference +- `python-contact-form.md` - Python contact form implementation +- `python-flask.md` - Flask forms tutorial +- `python-flask-app.md` - Building Flask web applications +- `python-as-web-framework.md` - Python web framework basics + +### Data & Network +- `xml.md` - XML data format reference +- `hypertext-transfer-protocol.md` - HTTP protocol reference +- `security.md` - Web security best practices +- `web-api.md` - Web API integration +- `web-performance.md` - Performance optimization techniques + +## Usage + +When creating a web form, consult the appropriate reference files based on your needs: + +1. **Planning**: Review `form-basics.md` and `form-controls.md` +2. **Structure**: Use `html-form-elements.md` and `aria-form-role.md` +3. **Styling**: Reference `styling-web-forms.md` and `css-styling.md` +4. **Interactivity**: Apply techniques from `javascript.md` +5. **Accessibility**: Follow guidelines in `accessibility.md` +6. **Server Processing**: Choose between PHP or Python references +7. **Data Storage**: Consult database and data format references +8. **Optimization**: Review `web-performance.md` and `security.md` + +## Best Practices + +- Always validate input on both client and server sides +- Ensure forms are accessible to all users +- Use semantic HTML elements +- Implement proper error handling and user feedback +- Secure form data transmission with HTTPS +- Follow progressive enhancement principles +- Test forms across different browsers and devices +- Optimize for performance and user experience diff --git a/skills/create-web-form/references/accessibility.md b/skills/create-web-form/references/accessibility.md new file mode 100644 index 00000000..e12bb69f --- /dev/null +++ b/skills/create-web-form/references/accessibility.md @@ -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/ | diff --git a/skills/create-web-form/references/aria-form-role.md b/skills/create-web-form/references/aria-form-role.md new file mode 100644 index 00000000..87b09550 --- /dev/null +++ b/skills/create-web-form/references/aria-form-role.md @@ -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) diff --git a/skills/create-web-form/references/css-styling.md b/skills/create-web-form/references/css-styling.md new file mode 100644 index 00000000..8f8a4112 --- /dev/null +++ b/skills/create-web-form/references/css-styling.md @@ -0,0 +1,1027 @@ +# CSS Styling Reference + +A consolidated reference covering CSS properties, selectors, pseudo-classes, at-rules, the box model, Flexbox, Grid, and media queries. + +--- + +## Table of Contents + +1. [CSS Properties Reference](#1-css-properties-reference) +2. [CSS Selectors](#2-css-selectors) +3. [Pseudo-Classes and Pseudo-Elements](#3-pseudo-classes-and-pseudo-elements) +4. [CSS At-Rules](#4-css-at-rules) +5. [CSS Styling Basics](#5-css-styling-basics) +6. [The Box Model](#6-the-box-model) +7. [Flexbox Layout](#7-flexbox-layout) +8. [Grid Layout](#8-grid-layout) +9. [Media Queries](#9-media-queries) + +--- + +## 1. CSS Properties Reference + +> Source: https://www.w3schools.com/cssref/index.php + +### Background + +| Property | Description | +|---|---| +| `background` | Shorthand for all background properties | +| `background-color` | Sets the background color | +| `background-image` | Sets one or more background images | +| `background-position` | Sets the starting position of a background image | +| `background-repeat` | Sets how a background image is repeated | +| `background-size` | Sets the size of the background image (`cover`, `contain`, length) | +| `background-attachment` | Sets whether background scrolls with content (`scroll`, `fixed`, `local`) | +| `background-clip` | Defines how far the background extends (`border-box`, `padding-box`, `content-box`) | +| `background-origin` | Specifies the positioning area of the background image | + +### Border + +| Property | Description | +|---|---| +| `border` | Shorthand for border-width, border-style, border-color | +| `border-width` | Sets the width of borders | +| `border-style` | Sets the style (`none`, `solid`, `dashed`, `dotted`, `double`, `groove`, `ridge`, `inset`, `outset`) | +| `border-color` | Sets the color of borders | +| `border-radius` | Sets rounded corners | +| `border-top` / `border-right` / `border-bottom` / `border-left` | Individual side borders | +| `border-collapse` | Sets whether table borders are collapsed into a single border | +| `border-spacing` | Sets the distance between borders of adjacent cells | +| `border-image` | Shorthand for using an image as a border | +| `outline` | A line drawn outside the border (does not take up space) | +| `outline-offset` | Adds space between an outline and the edge of an element | + +### Box Model / Dimensions + +| Property | Description | +|---|---| +| `width` / `height` | Sets element width/height | +| `min-width` / `min-height` | Sets minimum width/height | +| `max-width` / `max-height` | Sets maximum width/height | +| `margin` | Sets outer spacing (shorthand for top, right, bottom, left) | +| `padding` | Sets inner spacing (shorthand for top, right, bottom, left) | +| `box-sizing` | Defines how width/height are calculated (`content-box`, `border-box`) | +| `overflow` | Controls content overflow (`visible`, `hidden`, `scroll`, `auto`) | +| `overflow-x` / `overflow-y` | Controls horizontal/vertical overflow individually | + +### Color and Opacity + +| Property | Description | +|---|---| +| `color` | Sets the text color | +| `opacity` | Sets the transparency level (0.0 to 1.0) | + +### Display and Visibility + +| Property | Description | +|---|---| +| `display` | Controls display behavior (`block`, `inline`, `inline-block`, `flex`, `grid`, `none`, etc.) | +| `visibility` | Controls visibility (`visible`, `hidden`, `collapse`) | +| `float` | Places an element to the left or right of its container | +| `clear` | Specifies which sides of an element floating elements are not allowed | +| `position` | Sets positioning method (`static`, `relative`, `absolute`, `fixed`, `sticky`) | +| `top` / `right` / `bottom` / `left` | Offsets for positioned elements | +| `z-index` | Sets the stack order of positioned elements | + +### Typography / Font + +| Property | Description | +|---|---| +| `font` | Shorthand for font properties | +| `font-family` | Sets the font (e.g., `"Arial", sans-serif`) | +| `font-size` | Sets the size of text | +| `font-weight` | Sets boldness (`normal`, `bold`, `100`-`900`) | +| `font-style` | Sets style (`normal`, `italic`, `oblique`) | +| `font-variant` | Sets small-caps or other variants | +| `line-height` | Sets the line height / leading | +| `letter-spacing` | Sets spacing between characters | +| `word-spacing` | Sets spacing between words | + +### Text + +| Property | Description | +|---|---| +| `text-align` | Sets horizontal alignment (`left`, `right`, `center`, `justify`) | +| `text-decoration` | Adds decoration to text (`none`, `underline`, `overline`, `line-through`) | +| `text-transform` | Controls capitalization (`uppercase`, `lowercase`, `capitalize`) | +| `text-indent` | Indents the first line of a text block | +| `text-shadow` | Adds shadow to text | +| `white-space` | Controls how whitespace is handled | +| `word-break` | Controls line breaking rules for words | +| `word-wrap` / `overflow-wrap` | Allows long words to break and wrap to next line | +| `vertical-align` | Sets vertical alignment of inline or table-cell elements | +| `direction` | Sets text direction (`ltr`, `rtl`) | + +### List + +| Property | Description | +|---|---| +| `list-style` | Shorthand for list properties | +| `list-style-type` | Sets the bullet type (`disc`, `circle`, `square`, `decimal`, `none`, etc.) | +| `list-style-position` | Sets marker position (`inside`, `outside`) | +| `list-style-image` | Uses an image as the list marker | + +### Table + +| Property | Description | +|---|---| +| `border-collapse` | Merges table cell borders (`collapse`, `separate`) | +| `border-spacing` | Sets spacing between cells (when `separate`) | +| `caption-side` | Sets position of table caption (`top`, `bottom`) | +| `empty-cells` | Controls display of empty cells (`show`, `hide`) | +| `table-layout` | Sets table layout algorithm (`auto`, `fixed`) | + +### Transform and Transition + +| Property | Description | +|---|---| +| `transform` | Applies 2D or 3D transformations (`translate`, `rotate`, `scale`, `skew`, `matrix`) | +| `transform-origin` | Sets the origin point for transformations | +| `transition` | Shorthand for transition properties | +| `transition-property` | Specifies which properties to transition | +| `transition-duration` | Sets how long the transition takes | +| `transition-timing-function` | Sets the speed curve (`ease`, `linear`, `ease-in`, `ease-out`, `ease-in-out`, `cubic-bezier()`) | +| `transition-delay` | Sets a delay before the transition starts | + +### Animation + +| Property | Description | +|---|---| +| `animation` | Shorthand for animation properties | +| `animation-name` | Names the `@keyframes` animation | +| `animation-duration` | How long the animation takes | +| `animation-timing-function` | Speed curve of the animation | +| `animation-delay` | Delay before starting | +| `animation-iteration-count` | Number of times to repeat (`infinite` for looping) | +| `animation-direction` | Whether the animation alternates direction (`normal`, `reverse`, `alternate`) | +| `animation-fill-mode` | Styles applied before/after animation (`none`, `forwards`, `backwards`, `both`) | +| `animation-play-state` | Pauses or runs the animation (`running`, `paused`) | + +### Flexbox (Container) + +| Property | Description | +|---|---| +| `display: flex` | Creates a flex container | +| `flex-direction` | Sets main axis direction (`row`, `column`, `row-reverse`, `column-reverse`) | +| `flex-wrap` | Controls wrapping (`nowrap`, `wrap`, `wrap-reverse`) | +| `flex-flow` | Shorthand for `flex-direction` and `flex-wrap` | +| `justify-content` | Aligns items along the main axis | +| `align-items` | Aligns items along the cross axis | +| `align-content` | Aligns wrapped lines | +| `gap` / `row-gap` / `column-gap` | Sets spacing between flex items | + +### Flexbox (Items) + +| Property | Description | +|---|---| +| `flex` | Shorthand for `flex-grow`, `flex-shrink`, `flex-basis` | +| `flex-grow` | How much the item grows relative to others | +| `flex-shrink` | How much the item shrinks relative to others | +| `flex-basis` | Default size before distributing space | +| `order` | Sets visual order of flex items | +| `align-self` | Overrides container `align-items` for one item | + +### Grid (Container) + +| Property | Description | +|---|---| +| `display: grid` | Creates a grid container | +| `grid-template-columns` | Defines column track sizes | +| `grid-template-rows` | Defines row track sizes | +| `grid-template-areas` | Defines named grid areas | +| `grid-template` | Shorthand for rows, columns, areas | +| `gap` / `row-gap` / `column-gap` | Spacing between grid tracks | +| `grid-auto-rows` / `grid-auto-columns` | Size for implicitly created tracks | +| `grid-auto-flow` | Controls auto-placement algorithm (`row`, `column`, `dense`) | +| `justify-items` / `align-items` | Aligns items within their cells | +| `justify-content` / `align-content` | Aligns the grid within its container | + +### Grid (Items) + +| Property | Description | +|---|---| +| `grid-column` | Shorthand for `grid-column-start` / `grid-column-end` | +| `grid-row` | Shorthand for `grid-row-start` / `grid-row-end` | +| `grid-area` | Assigns item to a named area or shorthand for row/column placement | +| `justify-self` / `align-self` | Aligns an individual item within its cell | + +### Other Common Properties + +| Property | Description | +|---|---| +| `cursor` | Sets the mouse cursor type (`pointer`, `default`, `grab`, `text`, etc.) | +| `box-shadow` | Adds shadow effects to elements | +| `filter` | Applies graphical effects (`blur()`, `brightness()`, `contrast()`, `grayscale()`, etc.) | +| `clip-path` | Clips an element to a shape | +| `object-fit` | How replaced elements (img, video) fit their container (`fill`, `contain`, `cover`, `none`) | +| `object-position` | Position of replaced element content within its box | +| `resize` | Whether an element is resizable (`none`, `both`, `horizontal`, `vertical`) | +| `user-select` | Controls whether text can be selected (`none`, `auto`, `text`, `all`) | +| `pointer-events` | Controls whether an element reacts to pointer events | +| `content` | Used with `::before` and `::after` pseudo-elements | +| `counter-reset` / `counter-increment` | Creates and increments CSS counters | +| `will-change` | Hints to the browser about upcoming changes for optimization | +| `aspect-ratio` | Sets a preferred aspect ratio for the element | +| `accent-color` | Sets the accent color for form controls | +| `scroll-behavior` | Controls smooth scrolling (`auto`, `smooth`) | + +--- + +## 2. CSS Selectors + +> Source: https://www.w3schools.com/cssref/css_selectors.php + +### Basic Selectors + +| Selector | Example | Description | +|---|---|---| +| `*` | `* { }` | Selects all elements | +| `element` | `p { }` | Selects all `<p>` elements | +| `.class` | `.intro { }` | Selects all elements with `class="intro"` | +| `#id` | `#firstname { }` | Selects the element with `id="firstname"` | +| `element.class` | `p.intro { }` | Selects `<p>` elements with `class="intro"` | + +### Grouping + +| Selector | Example | Description | +|---|---|---| +| `sel1, sel2` | `div, p { }` | Selects all `<div>` and all `<p>` elements | + +### Combinator Selectors + +| Selector | Example | Description | +|---|---|---| +| `ancestor descendant` | `div p { }` | Selects all `<p>` inside `<div>` (any depth) | +| `parent > child` | `div > p { }` | Selects `<p>` that are direct children of `<div>` | +| `element + sibling` | `div + p { }` | Selects the first `<p>` immediately after `<div>` | +| `element ~ siblings` | `div ~ p { }` | Selects all `<p>` that are siblings after `<div>` | + +### Attribute Selectors + +| Selector | Example | Description | +|---|---|---| +| `[attr]` | `[target] { }` | Elements with a `target` attribute | +| `[attr=value]` | `[target="_blank"] { }` | Elements where `target` equals `_blank` | +| `[attr~=value]` | `[title~="flower"] { }` | Attribute contains the word `flower` | +| `[attr\|=value]` | `[lang\|="en"] { }` | Attribute starts with `en` (exact or followed by `-`) | +| `[attr^=value]` | `a[href^="https"] { }` | Attribute value begins with `https` | +| `[attr$=value]` | `a[href$=".pdf"] { }` | Attribute value ends with `.pdf` | +| `[attr*=value]` | `a[href*="w3schools"] { }` | Attribute value contains `w3schools` | + +--- + +## 3. Pseudo-Classes and Pseudo-Elements + +> Source: https://www.w3schools.com/cssref/css_ref_pseudo_classes.php + +### Pseudo-Classes + +Pseudo-classes select elements based on state or position. + +**Link and User Action States:** + +| Pseudo-Class | Description | +|---|---| +| `:link` | Unvisited links | +| `:visited` | Visited links | +| `:hover` | Element being hovered over | +| `:active` | Element being activated (e.g., clicked) | +| `:focus` | Element that has focus | +| `:focus-within` | Element that contains a focused element | +| `:focus-visible` | Element focused via keyboard (not mouse) | + +**Form / Input States:** + +| Pseudo-Class | Description | +|---|---| +| `:checked` | Checked checkbox or radio button | +| `:disabled` | Disabled form elements | +| `:enabled` | Enabled form elements | +| `:required` | Form elements with `required` attribute | +| `:optional` | Form elements without `required` attribute | +| `:valid` | Form elements with valid values | +| `:invalid` | Form elements with invalid values | +| `:in-range` | Input values within a specified range | +| `:out-of-range` | Input values outside a specified range | +| `:read-only` | Elements with `readonly` attribute | +| `:read-write` | Elements without `readonly` attribute | +| `:placeholder-shown` | Input elements currently showing placeholder text | +| `:default` | The default form element | +| `:indeterminate` | Checkbox/radio with indeterminate state | + +**Structural Pseudo-Classes:** + +| Pseudo-Class | Description | +|---|---| +| `:first-child` | First child of its parent | +| `:last-child` | Last child of its parent | +| `:nth-child(n)` | The nth child (`n`, `2n`, `odd`, `even`, `3n+1`, etc.) | +| `:nth-last-child(n)` | The nth child counting from the end | +| `:only-child` | Only child of its parent | +| `:first-of-type` | First element of its type within parent | +| `:last-of-type` | Last element of its type within parent | +| `:nth-of-type(n)` | The nth element of its type | +| `:nth-last-of-type(n)` | The nth element of its type counting from end | +| `:only-of-type` | Only element of its type within parent | +| `:root` | The document root element (usually `<html>`) | +| `:empty` | Elements with no children or text | + +**Other Pseudo-Classes:** + +| Pseudo-Class | Description | +|---|---| +| `:not(selector)` | Elements that do NOT match the selector | +| `:is(selector)` | Matches any element that matches one of the selectors in the list | +| `:where(selector)` | Same as `:is()` but with zero specificity | +| `:has(selector)` | Parent selector -- matches if the element has a descendant matching the selector | +| `:target` | Element whose ID matches the URL fragment (e.g., `#section1`) | +| `:lang(language)` | Elements with a specified language attribute | + +### Pseudo-Elements + +Pseudo-elements style specific parts of an element. + +| Pseudo-Element | Description | +|---|---| +| `::before` | Inserts content before the element's content | +| `::after` | Inserts content after the element's content | +| `::first-line` | Styles the first line of a block element | +| `::first-letter` | Styles the first letter of a block element | +| `::selection` | Styles the portion selected/highlighted by the user | +| `::placeholder` | Styles the placeholder text of an input | +| `::marker` | Styles the marker (bullet/number) of list items | +| `::backdrop` | Styles the backdrop behind a dialog or fullscreen element | + +--- + +## 4. CSS At-Rules + +> Source: https://www.w3schools.com/cssref/css_ref_atrules.php + +| At-Rule | Description | +|---|---| +| `@charset` | Specifies the character encoding of the stylesheet (e.g., `@charset "UTF-8";`) | +| `@import` | Imports an external stylesheet (`@import url("style.css");`) | +| `@font-face` | Defines a custom font to be used in the document | +| `@keyframes` | Defines animation keyframes for `animation-name` | +| `@media` | Applies styles conditionally based on media queries | +| `@supports` | Applies styles only if the browser supports a given CSS feature | +| `@page` | Defines styles for printed pages (margins, size, etc.) | +| `@layer` | Declares cascade layers to control specificity ordering | +| `@container` | Applies styles based on the size of a container element | +| `@property` | Registers a custom property with a defined syntax, inheritance, and initial value | +| `@scope` | Limits styles to a specific DOM subtree | +| `@starting-style` | Defines styles for CSS transitions when an element first appears | +| `@counter-style` | Defines custom counter styles for list markers | +| `@namespace` | Declares an XML namespace for use in CSS selectors | +| `@color-profile` | Defines a color profile for use with `color()` function | + +### Common At-Rule Examples + +```css +/* @font-face -- define a custom font */ +@font-face { + font-family: "MyFont"; + src: url("myfont.woff2") format("woff2"), + url("myfont.woff") format("woff"); + font-weight: normal; + font-style: normal; + font-display: swap; +} + +/* @keyframes -- define an animation */ +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +/* @media -- responsive styles */ +@media screen and (max-width: 768px) { + .container { flex-direction: column; } +} + +/* @supports -- feature detection */ +@supports (display: grid) { + .container { display: grid; } +} + +/* @layer -- cascade layers */ +@layer base, components, utilities; +@layer base { + body { margin: 0; } +} + +/* @container -- container queries */ +@container (min-width: 400px) { + .card { grid-template-columns: 1fr 1fr; } +} +``` + +--- + +## 5. CSS Styling Basics + +> Source: https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics + +### What is CSS? + +**CSS (Cascading Style Sheets)** is used to style and lay out web pages. It controls fonts, colors, sizes, spacing, layout, animations, and other visual aspects. + +### CSS Syntax + +```css +selector { + property: value; + property: value; +} +``` + +A **rule** (or **ruleset**) consists of a **selector** and a **declaration block** containing one or more **declarations** (property-value pairs). + +### Applying CSS to HTML + +There are three ways to apply CSS: + +1. **External Stylesheet** (recommended): + ```html + <link rel="stylesheet" href="styles.css"> + ``` + +2. **Internal Stylesheet**: + ```html + <style> + p { color: red; } + </style> + ``` + +3. **Inline Styles** (avoid when possible): + ```html + <p style="color: red;">Text</p> + ``` + +### The Cascade, Specificity, and Inheritance + +- **Cascade**: When multiple rules target the same element, later rules override earlier ones (all else being equal). +- **Specificity**: More specific selectors override less specific ones. Specificity ranking (low to high): + - Type selectors (`p`, `div`) and pseudo-elements + - Class selectors (`.intro`), attribute selectors, and pseudo-classes + - ID selectors (`#main`) + - Inline styles + - `!important` (overrides all, use sparingly) +- **Inheritance**: Some properties (mostly text-related) are inherited by child elements; others (mostly layout-related) are not. + +### Values and Units + +| Unit | Type | Description | +|---|---|---| +| `px` | Absolute | Pixels (most common absolute unit) | +| `em` | Relative | Relative to parent element font size | +| `rem` | Relative | Relative to root element font size | +| `%` | Relative | Percentage of parent element's value | +| `vw` / `vh` | Relative | 1% of viewport width / height | +| `vmin` / `vmax` | Relative | 1% of the smaller/larger viewport dimension | +| `ch` | Relative | Width of the `0` character | +| `fr` | Fraction | Fraction of available space (Grid only) | + +### Color Values + +```css +color: red; /* Named color */ +color: #ff0000; /* Hex */ +color: #f00; /* Hex shorthand */ +color: rgb(255, 0, 0); /* RGB */ +color: rgba(255, 0, 0, 0.5); /* RGB with alpha */ +color: rgb(255 0 0 / 50%); /* Modern RGB syntax */ +color: hsl(0, 100%, 50%); /* HSL */ +color: hsla(0, 100%, 50%, 0.5); /* HSL with alpha */ +color: hsl(0 100% 50% / 50%); /* Modern HSL syntax */ +``` + +--- + +## 6. The Box Model + +> Source: https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics/Box_model + +### The Four Layers + +Every CSS element is surrounded by a box with four layers (inside to outside): + +1. **Content Box** -- where content is displayed; sized with `width` and `height` +2. **Padding Box** -- space around content; sized with `padding` +3. **Border Box** -- wraps content and padding; sized with `border` +4. **Margin Box** -- outermost space around the element; sized with `margin` + +### Standard vs. Alternative Box Model + +**Standard (default -- `content-box`):** +```css +.box { + width: 350px; /* Content width only */ + padding: 25px; + border: 5px solid black; + margin: 10px; +} +/* Total rendered width: 350 + 25 + 25 + 5 + 5 = 410px */ +``` + +**Alternative (`border-box`):** +```css +.box { + box-sizing: border-box; + width: 350px; /* Includes padding and border */ + padding: 25px; + border: 5px solid black; + margin: 10px; +} +/* Total rendered width: 350px (content area shrinks to fit) */ +``` + +**Recommended global reset:** +```css +html { + box-sizing: border-box; +} + +*, +*::before, +*::after { + box-sizing: inherit; +} +``` + +### Block vs. Inline vs. Inline-Block + +| Behavior | Block | Inline | Inline-Block | +|---|---|---|---| +| Breaks onto new line | Yes | No | No | +| Respects `width`/`height` | Yes | No | Yes | +| Padding/margin push others away | Yes | Left/right only | Yes | +| Fills container width by default | Yes | No | No | +| Common elements | `div`, `p`, `h1`-`h6`, `section` | `a`, `span`, `em`, `strong` | -- (set via CSS) | + +### Margin Collapsing + +When vertical margins of adjacent block elements touch, they collapse: + +- **Two positive margins**: The larger value wins +- **Two negative margins**: The smallest (most negative) value wins +- **One positive + one negative**: They are subtracted from each other + +```css +.one { margin-bottom: 50px; } +.two { margin-top: 30px; } +/* Result: 50px gap between them (not 80px) */ +``` + +### Shorthand Notation + +```css +/* All four sides */ +margin: 10px; /* All sides 10px */ +margin: 10px 20px; /* Vertical 10px, Horizontal 20px */ +margin: 10px 20px 30px; /* Top 10px, Horizontal 20px, Bottom 30px */ +margin: 10px 20px 30px 40px; /* Top, Right, Bottom, Left (clockwise) */ +``` + +--- + +## 7. Flexbox Layout + +> Source: https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/CSS_layout/Flexbox + +Flexbox is a **one-dimensional** layout method for arranging items in rows or columns. + +### Axes + +- **Main Axis**: The direction items are laid out (default: horizontal) +- **Cross Axis**: Perpendicular to the main axis (default: vertical) + +### Container Properties + +```css +.container { + display: flex; /* or inline-flex */ + + /* Direction */ + flex-direction: row; /* row | row-reverse | column | column-reverse */ + + /* Wrapping */ + flex-wrap: nowrap; /* nowrap | wrap | wrap-reverse */ + + /* Shorthand for direction + wrap */ + flex-flow: row wrap; + + /* Main axis alignment */ + justify-content: flex-start; /* flex-start | flex-end | center | + space-between | space-around | space-evenly */ + + /* Cross axis alignment */ + align-items: stretch; /* stretch | flex-start | flex-end | + center | baseline */ + + /* Multi-line cross axis alignment (when wrapping) */ + align-content: stretch; /* stretch | flex-start | flex-end | center | + space-between | space-around */ + + /* Spacing */ + gap: 10px; /* row-gap and column-gap shorthand */ +} +``` + +### Item Properties + +```css +.item { + /* Growth/shrink behavior (shorthand) */ + flex: 1; /* flex-grow: 1, flex-shrink: 1, flex-basis: 0 */ + flex: 1 200px; /* flex-grow: 1, flex-basis: 200px */ + + /* Individual properties */ + flex-grow: 0; /* How much the item grows (0 = don't grow) */ + flex-shrink: 1; /* How much the item shrinks (0 = don't shrink) */ + flex-basis: auto; /* Default size before space distribution */ + + /* Visual ordering */ + order: 0; /* Lower values appear first; default is 0 */ + + /* Individual cross-axis alignment */ + align-self: auto; /* auto | flex-start | flex-end | center | + baseline | stretch */ +} +``` + +### Common Patterns + +```css +/* Equal-width columns */ +.item { flex: 1; } + +/* Centering an item vertically and horizontally */ +.container { + display: flex; + justify-content: center; + align-items: center; +} + +/* Responsive wrapping layout */ +.container { + display: flex; + flex-wrap: wrap; + gap: 1rem; +} +.item { + flex: 1 1 300px; /* Grow, shrink, min-width 300px */ +} + +/* Sticky footer layout */ +body { + display: flex; + flex-direction: column; + min-height: 100vh; +} +main { flex: 1; } +``` + +--- + +## 8. Grid Layout + +> Source: https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/CSS_layout/Grids + +CSS Grid is a **two-dimensional** layout system for organizing content into rows and columns. + +### Container Properties + +```css +.container { + display: grid; /* or inline-grid */ + + /* Define columns and rows */ + grid-template-columns: 200px 1fr 200px; + grid-template-rows: auto 1fr auto; + + /* Using repeat() */ + grid-template-columns: repeat(3, 1fr); + + /* Responsive auto-fill / auto-fit */ + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + + /* Named areas */ + grid-template-areas: + "header header header" + "sidebar content content" + "footer footer footer"; + + /* Gaps between tracks */ + gap: 20px; + column-gap: 20px; + row-gap: 20px; + + /* Size for implicitly created tracks */ + grid-auto-rows: minmax(100px, auto); + grid-auto-columns: 1fr; + + /* Auto-placement algorithm */ + grid-auto-flow: row; /* row | column | dense */ + + /* Align all items within their cells */ + justify-items: stretch; /* start | end | center | stretch */ + align-items: stretch; /* start | end | center | stretch */ + + /* Align the grid within its container */ + justify-content: start; /* start | end | center | stretch | + space-between | space-around | space-evenly */ + align-content: start; +} +``` + +### Key Functions + +| Function | Description | +|---|---| +| `repeat(count, size)` | Repeats a track definition (e.g., `repeat(3, 1fr)`) | +| `minmax(min, max)` | Sets a minimum and maximum size for a track | +| `auto-fill` | Creates as many tracks as fit the container (empty tracks remain) | +| `auto-fit` | Creates as many tracks as fit, then collapses empty tracks | +| `fit-content(max)` | Sizes track to content, up to a maximum | + +### The `fr` Unit + +The `fr` unit represents one fraction of available space: +```css +grid-template-columns: 2fr 1fr 1fr; +/* First column gets 50%, others get 25% each */ +``` + +### Item Properties + +```css +.item { + /* Placement by line numbers */ + grid-column: 1 / 3; /* Start at line 1, end at line 3 */ + grid-row: 1 / 2; + + /* Placement by span */ + grid-column: 1 / span 2; /* Start at line 1, span 2 columns */ + + /* Full-width item */ + grid-column: 1 / -1; /* Line 1 to the last line */ + + /* Placement by named area */ + grid-area: header; + + /* Self-alignment within cell */ + justify-self: center; /* start | end | center | stretch */ + align-self: center; +} +``` + +### Named Grid Areas Example + +```css +.container { + display: grid; + grid-template-columns: 1fr 3fr; + grid-template-areas: + "header header" + "sidebar content" + "footer footer"; + gap: 20px; +} + +header { grid-area: header; } +aside { grid-area: sidebar; } +main { grid-area: content; } +footer { grid-area: footer; } +``` + +### Subgrid + +A grid item can inherit its parent's track definitions: +```css +.nested { + display: grid; + grid-template-columns: subgrid; +} +``` + +### Explicit vs. Implicit Grid + +- **Explicit grid**: Tracks defined by `grid-template-columns` / `grid-template-rows` +- **Implicit grid**: Auto-generated tracks for content that overflows; controlled by `grid-auto-rows` / `grid-auto-columns` + +--- + +## 9. Media Queries + +> Source: https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/CSS_layout/Media_queries + +### Syntax + +```css +@media media-type and (media-feature) { + /* CSS rules */ +} +``` + +### Media Types + +| Type | Description | +|---|---| +| `all` | All devices (default) | +| `screen` | Screens (monitors, phones, tablets) | +| `print` | Print preview and printed pages | + +### Common Media Features + +| Feature | Description | Example | +|---|---|---| +| `width` / `min-width` / `max-width` | Viewport width | `(min-width: 768px)` | +| `height` / `min-height` / `max-height` | Viewport height | `(min-height: 600px)` | +| `orientation` | Portrait or landscape | `(orientation: landscape)` | +| `hover` | Can the user hover? | `(hover: hover)` | +| `pointer` | Pointing device precision | `(pointer: fine)` or `(pointer: coarse)` | +| `prefers-color-scheme` | User's color scheme preference | `(prefers-color-scheme: dark)` | +| `prefers-reduced-motion` | User prefers reduced motion | `(prefers-reduced-motion: reduce)` | +| `aspect-ratio` | Viewport aspect ratio | `(aspect-ratio: 16/9)` | +| `resolution` | Device pixel density | `(min-resolution: 2dppx)` | + +### Logical Operators + +```css +/* AND -- all conditions must be true */ +@media screen and (min-width: 600px) and (orientation: landscape) { } + +/* OR -- comma-separated; any condition can be true */ +@media (min-width: 600px), (orientation: landscape) { } + +/* NOT -- negates the entire query */ +@media not screen and (min-width: 600px) { } + +/* Range syntax (modern) */ +@media (30em <= width <= 50em) { } +``` + +### Mobile-First Responsive Design + +Start with mobile styles, then add complexity for larger screens: + +```css +/* Base styles (mobile) */ +.container { + width: 90%; + margin: 0 auto; +} + +/* Medium screens (tablets) */ +@media screen and (min-width: 40em) { + .container { + display: grid; + grid-template-columns: 3fr 1fr; + gap: 20px; + } + + nav ul { + display: flex; + } +} + +/* Large screens (desktop) */ +@media screen and (min-width: 70em) { + .container { + max-width: 1200px; + } +} +``` + +### Viewport Meta Tag (Required) + +Always include this in your HTML `<head>` for responsive design to work on mobile: + +```html +<meta name="viewport" content="width=device-width, initial-scale=1"> +``` + +### Common Breakpoints + +While there are no universal breakpoints, commonly used values include: + +| Label | Breakpoint | +|---|---| +| Small phones | `< 576px` | +| Phones / large phones | `>= 576px` | +| Tablets | `>= 768px` | +| Desktops | `>= 992px` | +| Large desktops | `>= 1200px` | +| Extra large | `>= 1400px` | + +**Best practice**: Do not target specific devices. Instead, add breakpoints where your content needs them -- when line lengths get too long or layouts break. + +### Responsive Without Media Queries + +Modern CSS layout methods can be inherently responsive: + +```css +/* Auto-responsive grid -- no media query needed */ +.grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 1rem; +} + +/* Fluid typography */ +h1 { + font-size: clamp(1.5rem, 4vw, 3rem); +} +``` + +### Print Styles + +```css +@media print { + nav, .sidebar, footer { + display: none; + } + + body { + font-size: 12pt; + color: black; + background: white; + } + + a[href]::after { + content: " (" attr(href) ")"; + } +} +``` + +### Dark Mode Support + +```css +@media (prefers-color-scheme: dark) { + :root { + --bg-color: #1a1a1a; + --text-color: #e0e0e0; + } + + body { + background-color: var(--bg-color); + color: var(--text-color); + } +} +``` + +--- + +## Quick Syntax Cheat Sheet + +```css +/* Variables (Custom Properties) */ +:root { + --primary: #3498db; + --spacing: 1rem; +} +.element { + color: var(--primary); + padding: var(--spacing); +} + +/* Nesting (modern CSS) */ +.card { + background: white; + & .title { + font-size: 1.5rem; + } + &:hover { + box-shadow: 0 4px 8px rgba(0,0,0,0.1); + } +} + +/* Logical Properties */ +margin-inline: auto; /* left + right margin */ +margin-block: 1rem; /* top + bottom margin */ +padding-inline-start: 1rem; /* left in LTR, right in RTL */ + +/* Container Queries */ +.card-container { + container-type: inline-size; +} +@container (min-width: 400px) { + .card { flex-direction: row; } +} + +/* Scroll Snap */ +.scroll-container { + scroll-snap-type: x mandatory; +} +.scroll-item { + scroll-snap-align: start; +} +``` + +--- + +*This reference was compiled from content at w3schools.com and developer.mozilla.org (MDN Web Docs). For full details, visit the source URLs listed above each section.* diff --git a/skills/create-web-form/references/form-basics.md b/skills/create-web-form/references/form-basics.md new file mode 100644 index 00000000..4ea2043f --- /dev/null +++ b/skills/create-web-form/references/form-basics.md @@ -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. diff --git a/skills/create-web-form/references/form-controls.md b/skills/create-web-form/references/form-controls.md new file mode 100644 index 00000000..6654b38e --- /dev/null +++ b/skills/create-web-form/references/form-controls.md @@ -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 | diff --git a/skills/create-web-form/references/form-data-handling.md b/skills/create-web-form/references/form-data-handling.md new file mode 100644 index 00000000..d4846d73 --- /dev/null +++ b/skills/create-web-form/references/form-data-handling.md @@ -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. diff --git a/skills/create-web-form/references/html-form-elements.md b/skills/create-web-form/references/html-form-elements.md new file mode 100644 index 00000000..dd0a4d13 --- /dev/null +++ b/skills/create-web-form/references/html-form-elements.md @@ -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; +} +``` diff --git a/skills/create-web-form/references/html-form-example.md b/skills/create-web-form/references/html-form-example.md new file mode 100644 index 00000000..5d6c1d89 --- /dev/null +++ b/skills/create-web-form/references/html-form-example.md @@ -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`) | diff --git a/skills/create-web-form/references/hypertext-transfer-protocol.md b/skills/create-web-form/references/hypertext-transfer-protocol.md new file mode 100644 index 00000000..962f10c0 --- /dev/null +++ b/skills/create-web-form/references/hypertext-transfer-protocol.md @@ -0,0 +1,1227 @@ +# Hypertext Transfer Protocol (HTTP) Reference + +A consolidated reference guide covering the HTTP protocol, its messages, cookies, authentication, sessions, headers, methods, status codes, and specifications. All content sourced from the Mozilla Developer Network (MDN) Web Docs. + +--- + +## Table of Contents + +1. [HTTP Overview (Introduction)](#1-http-overview) +2. [An Overview of HTTP](#2-an-overview-of-http) +3. [HTTP Messages](#3-http-messages) +4. [HTTP Cookies](#4-http-cookies) +5. [HTTP Authentication](#5-http-authentication) +6. [HTTP Sessions](#6-http-sessions) +7. [HTTP Headers Reference](#7-http-headers-reference) +8. [HTTP Request Methods](#8-http-request-methods) +9. [HTTP Response Status Codes](#9-http-response-status-codes) +10. [HTTP Resources and Specifications](#10-http-resources-and-specifications) + +--- + +## 1. HTTP Overview + +> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTTP> + +### Definition + +**HTTP (Hypertext Transfer Protocol)** is an application-layer protocol for transmitting hypermedia documents, such as HTML. While designed for communication between web browsers and web servers, it is also used for machine-to-machine communication and programmatic API access. + +### Key Characteristics + +- **Client-Server Model**: A classical architecture where a client opens a connection to make a request and waits for a server response. +- **Stateless Protocol**: The server does not keep session data between requests, though cookies add state capability. +- **Extensible**: Built on concepts of resources, URIs, and a basic message structure; the protocol has evolved with numerous extensions over time. + +### Major Topic Areas + +#### Guides (Foundational and Specialized) + +- **Overview of HTTP** -- Basic features and protocol stack position +- **Evolution of HTTP** -- HTTP/0.9, 1.0, 1.1, 2.0, and 3.0 +- **HTTP Messages** -- Request/response structure and types +- **MIME Types** -- Content-Type headers and standards +- **HTTP Caching** -- Methods and header controls +- **HTTP Authentication** -- Client identity verification +- **Cookies** -- Set-Cookie and Cookie headers for state management +- **Redirections** -- URL forwarding techniques (3xx status codes) +- **Conditional Requests** -- Validator-dependent outcomes +- **Range Requests** -- Partial resource retrieval +- **Content Negotiation** -- Accept headers and format preference +- **Connection Management (HTTP/1.x)** -- Persistent connections and pipelining +- **Protocol Upgrade** -- Upgrading to HTTP/2, WebSocket +- **Proxy Servers and Tunneling** +- **Client Hints** -- Device and preference metadata +- **Network Error Logging** -- Failed fetch reporting + +#### Security and Privacy + +- **Permissions Policy** -- Control feature access +- **CORS (Cross-Origin Resource Sharing)** -- Cross-site request handling +- **CSP (Content Security Policy)** -- Resource loading restrictions and attack mitigation +- **CORP (Cross-Origin Resource Policy)** -- Speculative side-channel attack prevention + +### Reference Documentation Summary + +- **HTTP Headers**: 169+ documented headers, including `Content-Type`, `Accept`, `Authorization`, `Cache-Control`, `Set-Cookie`, `Cookie`, `Access-Control-Allow-Origin`, `Content-Security-Policy`, and many more. +- **HTTP Request Methods**: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, `OPTIONS`, `CONNECT`, `TRACE`. +- **HTTP Response Status Codes**: Organized into five classes -- 1xx Informational, 2xx Successful, 3xx Redirection, 4xx Client Error, 5xx Server Error. + +### Tools and Resources + +- **Firefox Developer Tools** -- Network Monitor +- **HTTP Observatory** -- Site security configuration assessment +- **RedBot** -- Cache header validation +- **nghttp2** -- HTTP/2 client/server implementation +- **curl** -- Command-line data transfer tool + +--- + +## 2. An Overview of HTTP + +> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Overview> + +### What is HTTP? + +HTTP is a protocol for fetching resources such as HTML documents. It is the foundation of any data exchange on the Web and operates as a **client-server protocol**, where requests are initiated by the recipient (typically a web browser). Complete documents are constructed from multiple resources including text, layout instructions, images, videos, and scripts. + +HTTP is an **application layer protocol** sent over TCP or TLS-encrypted TCP connections. While designed in the early 1990s, it remains extensible and continues to evolve. + +### Architecture: Components of HTTP-Based Systems + +#### Client: The User-Agent + +- Any tool acting on behalf of the user (primarily web browsers). +- **Always** initiates requests; the server never initiates. +- Sends an initial request to fetch HTML documents, then makes additional requests for CSS, scripts, and sub-resources. +- Interprets HTTP responses and presents content to users. + +#### The Web Server + +- Serves documents as requested by clients. +- May be a single virtual machine or a collection of servers sharing load. +- With HTTP/1.1 and the `Host` header, multiple servers can share the same IP address. + +#### Proxies + +Located between client and server, proxies perform various functions: + +- **Caching** (public or private, like browser cache) +- **Filtering** (antivirus, parental controls) +- **Load balancing** (distribute requests across servers) +- **Authentication** (control resource access) +- **Logging** (store historical information) + +Proxies can be **transparent** (forward requests unchanged) or **non-transparent** (modify requests). + +### Basic Aspects of HTTP + +#### HTTP is Simple + +- Generally designed to be human-readable. +- HTTP messages can be read and understood by humans, providing easier testing for developers. + +#### HTTP is Extensible + +- **HTTP headers** make the protocol easy to extend and experiment with. +- New functionality can be introduced by agreement between client and server, a concept introduced in HTTP/1.0. + +#### HTTP is Stateless, But Not Sessionless + +- **Stateless**: No link between two successive requests on the same connection. +- Despite this, **HTTP Cookies** enable stateful sessions that allow sharing context and state across requests. + +#### HTTP and Connections + +HTTP requires a reliable transport protocol. TCP is connection-based and reliable while UDP is not. + +- **HTTP/1.0**: Opens a separate TCP connection for each request/response pair (inefficient). +- **HTTP/1.1**: Introduced **pipelining** and **persistent connections** via the `Connection` header. +- **HTTP/2**: Multiplexes messages over a single connection for efficiency. +- **Experimental**: The QUIC protocol is being tested as a transport layer (builds on UDP with reliability). + +### HTTP Flow + +When a client wants to communicate with a server: + +1. **Open a TCP connection**: Used to send request(s) and receive answer(s). Client may open new connection, reuse existing, or open several connections. + +2. **Send an HTTP message**: + + ``` + GET / HTTP/1.1 + Host: developer.mozilla.org + Accept-Language: fr + ``` + +3. **Read the response**: + + ``` + HTTP/1.1 200 OK + Date: Sat, 09 Oct 2010 14:28:02 GMT + Server: Apache + Last-Modified: Tue, 01 Dec 2009 20:18:22 GMT + ETag: "51142bc1-7449-479b075b2891b" + Accept-Ranges: bytes + Content-Length: 29769 + Content-Type: text/html + + <!doctype html>... (29769 bytes of requested web page) + ``` + +4. **Close or reuse connection** for further requests. + +### What Can Be Controlled by HTTP + +- **Caching**: Server instructs proxies and clients what to cache and for how long. +- **Relaxing the Origin Constraint**: Browsers enforce strict same-origin separation; HTTP headers can relax this via CORS. +- **Authentication**: Protected pages accessible only to specific users via `WWW-Authenticate` or HTTP Cookies. +- **Proxy and Tunneling**: Navigate network barriers, handle protocols like FTP through proxies. +- **Sessions**: HTTP Cookies link requests with server state, creating sessions despite the stateless protocol. + +### APIs Based on HTTP + +- **Fetch API**: The most commonly used API for HTTP requests from JavaScript, replacing the older `XMLHttpRequest` API. +- **Server-Sent Events**: A one-way service for the server to send events to the client using HTTP as a transport mechanism. + +--- + +## 3. HTTP Messages + +> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Messages> + +### Overview + +HTTP messages are the mechanism for exchanging data between server and client. There are two types: + +- **Requests**: Sent by the client to trigger an action on the server. +- **Responses**: The server's answer to a request. + +HTTP/1.x messages are text-based and straightforward to read. HTTP/2 wraps messages in binary framing but maintains the same underlying semantics. + +### HTTP Message Anatomy + +Both requests and responses share a common structure: + +``` +1. Start-line (single line describing HTTP version + request method or outcome) +2. HTTP Headers (optional metadata about the message) +3. Empty line (marks end of metadata) +4. Body (optional data associated with message) +``` + +The **start-line** and **headers** are collectively called the **head**. The content after is the **body**. + +### HTTP Requests + +#### Request-Line Format + +``` +<method> <request-target> <protocol> +``` + +#### Components + +**Method (HTTP Verb)**: Describes the meaning and desired outcome of the request. Common methods include `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, `OPTIONS`, `CONNECT`. Only `PATCH`, `POST`, and `PUT` requests typically have a body. + +**Request-Target (URL)** -- four types depending on context: + +1. **Origin Form** (most common): Absolute path with Host header. + ```http + GET /en-US/docs/Web/HTTP/Guides/Messages HTTP/1.1 + ``` + +2. **Absolute Form**: Complete URL; used with proxies. + ```http + GET https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Messages HTTP/1.1 + ``` + +3. **Authority Form**: Authority and port with colon; used with `CONNECT`. + ```http + CONNECT developer.mozilla.org:443 HTTP/1.1 + ``` + +4. **Asterisk Form**: Only with `OPTIONS` to represent the server as a whole. + ```http + OPTIONS * HTTP/1.1 + ``` + +**Protocol (HTTP Version)**: Usually `HTTP/1.1`. In HTTP/2+, the protocol version is not included in messages. + +#### Request Headers + +After the start-line and before the body. Case-insensitive, followed by colon and value: + +```http +Host: example.com +Content-Type: application/x-www-form-urlencoded +Content-Length: 49 +``` + +**Categories**: +- **Request Headers**: Provide additional context (e.g., conditional requests). +- **Representation Headers**: Describe the original form of message data and encoding applied. + +#### Request Body + +Only for `PATCH`, `POST`, and `PUT` methods. Examples: + +**Form data**: +``` +name=FirstName+LastName&email=bsmth%40example.com +``` + +**JSON**: +```json +{ + "firstName": "Brian", + "lastName": "Smith", + "email": "bsmth@example.com" +} +``` + +**Multipart form data**: +```http +--delimiter123 +Content-Disposition: form-data; name="field1" + +value1 +--delimiter123 +Content-Disposition: form-data; name="field2"; filename="example.txt" + +Text file contents +--delimiter123-- +``` + +### HTTP Responses + +#### Status-Line Format + +``` +<protocol> <status-code> <reason-phrase> +``` + +#### Components + +- **Protocol**: The HTTP version of the message. +- **Status Code**: Numeric code indicating request success or failure. + - 2xx Success: `200 OK`, `201 Created`, `204 No Content` + - 3xx Redirection: `302 Found`, `304 Not Modified` + - 4xx Client Error: `400 Bad Request`, `404 Not Found` + - 5xx Server Error: `500 Internal Server Error`, `503 Service Unavailable` +- **Reason Phrase**: Optional brief text description, e.g., "Created" or "Not Found". + +#### Response Headers + +Metadata sent with the response: + +```http +Content-Type: application/json +Content-Length: 256 +Cache-Control: max-age=604800 +Date: Fri, 13 Sep 2024 12:56:07 GMT +``` + +#### Response Body + +Included in most messages. May be: +- **Single-Resource Body**: Defined by `Content-Type` and `Content-Length` headers, or chunked with `Transfer-Encoding: chunked`. +- **Multiple-Resource Body**: Multiple parts with different information, associated with HTML forms and range requests. + +Note: Status codes like `201 Created` or `204 No Content` may not have a body. + +### HTTP/2 Messages + +Key differences from HTTP/1.x: + +- Wraps messages in binary frames (more efficient). +- Header compression via the HPACK algorithm. +- **Multiplexing**: Single TCP connection for multiple concurrent requests and responses. +- Eliminates head-of-line (HOL) blocking at the protocol level. + +HTTP/2 uses **pseudo-header fields** beginning with `:` instead of a start-line: + +**Request pseudo-headers**: +``` +:method: GET +:scheme: https +:authority: www.example.com +:path: / +``` + +**Response pseudo-header**: +``` +:status: 200 +``` + +### HTTP/3 Considerations + +- Uses QUIC (a protocol built on UDP instead of TCP). +- Fixes TCP-level head-of-line blocking. +- Reduced connection setup time. +- Enhanced stability on unreliable networks. +- Maintains the same core HTTP semantics (methods, status codes, headers). + +--- + +## 4. HTTP Cookies + +> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies> + +### What Are Cookies? + +A **cookie** (web cookie or browser cookie) is a small piece of data a server sends to a user's web browser. The browser may store cookies, create new ones, modify existing ones, and send them back to the same server with later requests. Cookies enable web applications to store limited amounts of data and remember state information. + +### Primary Use Cases + +1. **Session Management**: User sign-in status, shopping cart contents, game scores, and other session-related details. +2. **Personalization**: User preferences such as display language and UI theme. +3. **Tracking**: Recording and analyzing user behavior. + +### Setting Cookies + +#### Server-Side (HTTP Headers) + +Use the `Set-Cookie` response header: + +```http +HTTP/2.0 200 OK +Content-Type: text/html +Set-Cookie: yummy_cookie=chocolate +Set-Cookie: tasty_cookie=strawberry +``` + +#### Client-Side (JavaScript) + +Use the `Document.cookie` property: + +```javascript +document.cookie = "yummy_cookie=chocolate"; +document.cookie = "tasty_cookie=strawberry"; +console.log(document.cookie); +// logs "yummy_cookie=chocolate; tasty_cookie=strawberry" +``` + +### Sending Cookies + +When a new request is made to a domain, the browser automatically sends stored cookies via the `Cookie` request header: + +```http +GET /sample_page.html HTTP/2.0 +Host: www.example.org +Cookie: yummy_cookie=chocolate; tasty_cookie=strawberry +``` + +### Cookie Attributes + +#### Lifetime Control + +**Permanent Cookies** persist beyond the current session using `Expires` or `Max-Age`: + +```http +Set-Cookie: id=a3fWa; Expires=Thu, 31 Oct 2021 07:28:00 GMT; +Set-Cookie: id=a3fWa; Max-Age=2592000 +``` + +- `Expires`: Specifies an expiration date/time. +- `Max-Age`: Specifies duration in seconds (preferred over `Expires`; takes precedence if both are set). + +**Session Cookies** are deleted when the current session ends (no `Max-Age` or `Expires` attribute). + +#### Removing Cookies + +Set the cookie again with `Max-Age=0` or a past `Expires` date, or use the `Clear-Site-Data` header: + +```http +Set-Cookie: id=a3fWa; Max-Age=0 +Clear-Site-Data: "cookies" +``` + +#### Scope Control + +**Domain Attribute**: Specifies which domains can receive the cookie. + +```http +Set-Cookie: id=a3fWa; Domain=mozilla.org +``` + +- If not specified: cookie sent to the server that set it but NOT subdomains. +- If specified: sent to domain and all subdomains. + +**Path Attribute**: Specifies the URL path that must exist in the request URL. + +```http +Set-Cookie: id=a3fWa; Path=/docs +``` + +Matching paths: `/docs`, `/docs/`, `/docs/Web/`, `/docs/Web/HTTP`. Non-matching: `/`, `/docsets`, `/fr/docs`. + +#### Security Attributes + +**Secure**: Only sent over HTTPS (never with unsecured HTTP, except on localhost). + +```http +Set-Cookie: id=a3fWa; Secure +``` + +**HttpOnly**: Prevents JavaScript access via `Document.cookie`; only accessible via HTTP requests. Mitigates XSS attacks. + +```http +Set-Cookie: id=a3fWa; HttpOnly +``` + +**Combined**: + +```http +Set-Cookie: id=a3fWa; Expires=Thu, 21 Oct 2021 07:28:00 GMT; Secure; HttpOnly +``` + +#### SameSite Attribute + +Controls whether cookies are sent with cross-site requests: + +| Value | Behavior | +|-------|----------| +| **Strict** | Only sent in requests originating from the cookie's origin site. Use for sensitive functionality (authentication, cart). | +| **Lax** | Sent with site navigation but not with other cross-site requests. Default if `SameSite` is not set. | +| **None** | Sent with both originating and cross-site requests. Requires `Secure` attribute. | + +### Cookie Prefixes (Defense-in-Depth) + +- **`__Secure-`**: Must be set with `Secure` attribute by an HTTPS page. +- **`__Host-`**: Must be set with `Secure` attribute, cannot have `Domain` attribute, must have `Path=/`. +- **`__Http-`**: Must be set with `Secure` flag, must have `HttpOnly` attribute. + +### Security Best Practices + +1. Use `Secure` and `HttpOnly` attributes on sensitive cookies. +2. Limit scope with `Domain` and `Path` appropriately. +3. Control cross-site requests with `SameSite`. +4. Keep sensitive cookies short-lived. +5. Regenerate session cookies on authentication to prevent session fixation. +6. Store opaque identifiers instead of sensitive data directly in cookies. +7. Use cookie prefixes (`__Secure-`, `__Host-`) for defense-in-depth. + +### Storage Limitations + +- Maximum cookies per domain varies by browser, generally hundreds. +- Maximum size per cookie is usually 4KB. +- Modern alternatives for client-side storage: Web Storage API (`localStorage`, `sessionStorage`) and IndexedDB. + +### Privacy and Third-Party Cookies + +- Third-party cookies are set by embedded content from different domains. +- Most browser vendors now block third-party cookies by default. +- **Applicable regulations**: GDPR (EU), ePrivacy Directive (EU), California Consumer Privacy Act (US). + +### Key Related Headers + +- `Set-Cookie` -- Server sets cookies. +- `Cookie` -- Client sends cookies. +- `Clear-Site-Data` -- Clears cookies and other site data. + +### Specification + +RFC 6265 -- HTTP State Management Mechanism. + +--- + +## 5. HTTP Authentication + +> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Authentication> + +### General HTTP Authentication Framework + +HTTP authentication is defined in **RFC 7235** and provides a framework for access control using a challenge-and-response mechanism between servers and clients. + +#### Challenge-Response Flow + +1. **Server Challenge**: Server responds with `401 Unauthorized` status and includes a `WWW-Authenticate` response header with authentication challenge details. +2. **Client Response**: Client provides credentials via the `Authorization` request header. +3. **Retry**: Client typically presents a password prompt to the user, then reissues the request with correct credentials. + +### Authentication Headers + +#### WWW-Authenticate and Proxy-Authenticate + +Define the authentication method required to access a resource: + +```http +WWW-Authenticate: <type> realm=<realm> +Proxy-Authenticate: <type> realm=<realm> +``` + +- `<type>`: Authentication scheme (e.g., "Basic", "Bearer"). +- `realm`: Describes the protected area (e.g., "Access to the staging site"). + +#### Authorization and Proxy-Authorization + +Contain credentials to authenticate with the server or proxy: + +```http +Authorization: <type> <credentials> +Proxy-Authorization: <type> <credentials> +``` + +### Proxy Authentication + +Uses separate headers and status codes: + +- **Status Code**: `407 Proxy Authentication Required` +- **Response Header**: `Proxy-Authenticate` +- **Request Header**: `Proxy-Authorization` + +### Access Control Response Codes + +| Status | Meaning | Usage | +|--------|---------|-------| +| **401** | Unauthorized | Invalid credentials; user may retry | +| **403** | Forbidden | Valid credentials but inadequate permissions; no retry | +| **404** | Not Found | Sometimes preferred to hide resource existence from unauthorized users | +| **407** | Proxy Authentication Required | Proxy authentication failed | + +### Authentication Schemes + +| Scheme | Reference | Description | +|--------|-----------|-------------| +| **Basic** | RFC 7617 | Base64-encoded username:password (requires HTTPS) | +| **Bearer** | RFC 6750 | OAuth 2.0 bearer tokens | +| **Digest** | RFC 7616 | MD5 or SHA-256 hashing | +| **HOBA** | RFC 7486 | HTTP Origin-Bound Authentication (digital signature) | +| **Mutual** | RFC 8120 | Mutual authentication | +| **Negotiate/NTLM** | RFC 4559 | Windows integrated authentication | +| **VAPID** | RFC 8292 | Voluntary Application Server Identification | +| **SCRAM** | RFC 7804 | Salted Challenge Response Authentication Mechanism | +| **AWS4-HMAC-SHA256** | AWS Docs | AWS Signature Version 4 | + +Full list maintained by IANA: <https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml> + +### Basic Authentication Scheme + +- **Standard**: RFC 7617. +- **Format**: Transmits user ID and password as base64-encoded pairs (`username:password`). +- **Charset**: UTF-8. + +**Security Concerns**: +- Base64 is reversible; credentials appear as clear text. +- Always use HTTPS/TLS with Basic Auth. +- Vulnerable to CSRF; credentials sent in all requests regardless of origin. + +#### Apache Configuration + +`.htaccess` file: + +```apacheconf +AuthType Basic +AuthName "Access to the staging site" +AuthUserFile /path/to/.htpasswd +Require valid-user +``` + +#### Nginx Configuration + +```nginx +location /status { + auth_basic "Access to the staging site"; + auth_basic_user_file /etc/apache2/.htpasswd; +} +``` + +### Security Considerations + +- Cross-origin images cannot trigger HTTP authentication dialogs (Firefox 59+). +- Modern browsers use UTF-8 encoding for usernames and passwords. +- URL-embedded credentials (`https://username:password@www.example.com/`) are deprecated; modern browsers strip credentials from URLs before sending requests. + +--- + +## 6. HTTP Sessions + +> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Session> + +### Overview + +An HTTP session in client-server protocols consists of **three phases**: + +1. The client establishes a TCP connection (or appropriate transport layer connection). +2. The client sends its request and waits for the answer. +3. The server processes the request and sends back a response with status code and data. + +As of HTTP/1.1, the connection is no longer closed after completion, allowing the client to make further requests without re-establishing the connection. + +### Phase 1: Establishing a Connection + +- The **client** initiates the connection (not the server). +- HTTP typically uses **TCP** as the transport layer. +- **Default port**: 80 for HTTP servers (other ports like 8000, 8080 can also be used). +- The server cannot send data to the client without an explicit request, though this can be overcome using Push API, Server-sent events, or the WebSockets API. + +### Phase 2: Sending a Client Request + +A client request consists of text directives separated by CRLF, divided into three blocks: + +#### Block 1: Request Line + +Contains the request method, path of the document, and HTTP protocol version. + +#### Block 2: HTTP Headers + +Information about data types, language preferences, MIME types, and data modifying server behavior. Ends with an empty line that separates headers from the data block. + +#### Block 3: Optional Data Block + +Contains additional data, mainly used by the POST method. + +**Example GET Request**: + +```http +GET / HTTP/1.1 +Host: developer.mozilla.org +Accept-Language: fr + +``` + +**Example POST Request**: + +```http +POST /contact_form.php HTTP/1.1 +Host: developer.mozilla.org +Content-Length: 64 +Content-Type: application/x-www-form-urlencoded + +name=Joe%20User&request=Send%20me%20one%20of%20your%20catalogue +``` + +#### Common Request Methods + +| Method | Purpose | +|--------|---------| +| **GET** | Requests a data representation of the specified resource; should only retrieve data | +| **POST** | Sends data to the server to change its state; commonly used for HTML Forms | + +### Phase 3: Structure of Server Response + +Similar to requests, server responses are text directives separated by CRLF, divided into three blocks: + +#### Block 1: Status Line + +HTTP version acknowledgment, response status code, and brief human-readable meaning. + +#### Block 2: HTTP Headers + +Information about the data sent (type, size, compression, caching hints). Ends with an empty line. + +#### Block 3: Data Block + +Optional data or response content. + +**Example Successful Response (200 OK)**: + +```http +HTTP/1.1 200 OK +Content-Type: text/html; charset=utf-8 +Content-Length: 55743 +Connection: keep-alive +Cache-Control: s-maxage=300, public, max-age=0 +Content-Language: en-US +Date: Thu, 06 Dec 2018 17:37:18 GMT +ETag: "2e77ad1dc6ab0b53a2996dfd4653c1c3" +Server: meinheld/0.6.1 +Strict-Transport-Security: max-age=63072000 +X-Content-Type-Options: nosniff +X-Frame-Options: DENY +X-XSS-Protection: 1; mode=block +Vary: Accept-Encoding,Cookie +Age: 7 + +<!doctype html> +<html lang="en"> + ... +</html> +``` + +**Example Redirect (301)**: + +```http +HTTP/1.1 301 Moved Permanently +Server: Apache/2.4.37 (Red Hat) +Content-Type: text/html; charset=utf-8 +Location: https://developer.mozilla.org/ +``` + +**Example Error (404)**: + +```http +HTTP/1.1 404 Not Found +Content-Type: text/html; charset=utf-8 +Content-Length: 38217 +``` + +--- + +## 7. HTTP Headers Reference + +> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers> + +### Overview + +HTTP headers allow clients and servers to pass additional information with HTTP requests and responses. In HTTP/1.X, headers are case-insensitive name-value pairs (e.g., `Allow: POST`). In HTTP/2 and above, headers appear in lowercase and pseudo-headers are prefixed with a colon (e.g., `:status: 200`). + +### Header Categories by Context + +- **Request Headers**: Contain information about the resource to be fetched or about the client requesting the resource. +- **Response Headers**: Hold additional information about the response, such as location or server details. +- **Representation Headers**: Contain information about the resource body, including MIME type, encoding, and compression. +- **Payload Headers**: Contain representation-independent information about payload data, including content length and transport encoding. + +### Header Categories by Proxy Handling + +- **End-to-End Headers**: Must be transmitted to the final recipient. Intermediate proxies must retransmit them unmodified and caches must store them. +- **Hop-by-Hop Headers**: Meaningful only for a single transport-level connection. Must not be retransmitted by proxies or cached. + +### Authentication Headers + +| Header | Type | Description | +|--------|------|-------------| +| `WWW-Authenticate` | Response | Defines the authentication method to access a resource | +| `Authorization` | Request | Contains credentials to authenticate a user-agent with a server | +| `Proxy-Authenticate` | Response | Defines authentication method for proxy server access | +| `Proxy-Authorization` | Request | Contains credentials to authenticate with a proxy server | + +### Caching Headers + +| Header | Type | Description | +|--------|------|-------------| +| `Age` | Response | Time in seconds the object has been in a proxy cache | +| `Cache-Control` | Both | Directives for caching mechanisms in requests and responses | +| `Clear-Site-Data` | Response | Clears browsing data (cookies, storage, cache) | +| `Expires` | Response | Date/time after which response is considered stale | + +### Conditional Headers + +| Header | Type | Description | +|--------|------|-------------| +| `Last-Modified` | Response | Last modification date of the resource | +| `ETag` | Response | Unique string identifying the resource version | +| `If-Match` | Request | Applies method only if resource matches given ETags | +| `If-None-Match` | Request | Applies method if resource does not match given ETags | +| `If-Modified-Since` | Request | Transmits resource only if modified after given date | +| `If-Unmodified-Since` | Request | Transmits resource only if not modified after date | +| `Vary` | Response | Determines how to match headers for cache decisions | + +### Connection Management Headers + +| Header | Type | Description | +|--------|------|-------------| +| `Connection` | Both | Controls whether network connection stays open | +| `Keep-Alive` | Both | Controls how long a persistent connection stays open | + +### Content Negotiation Headers + +| Header | Type | Description | +|--------|------|-------------| +| `Accept` | Request | Informs server about acceptable data types | +| `Accept-Encoding` | Request | Specifies acceptable compression algorithms | +| `Accept-Language` | Request | Informs server about preferred human language | +| `Accept-Patch` | Response | Advertises media types acceptable in PATCH requests | +| `Accept-Post` | Response | Advertises media types acceptable in POST requests | + +### Cookie Headers + +| Header | Type | Description | +|--------|------|-------------| +| `Cookie` | Request | Contains HTTP cookies previously set by server | +| `Set-Cookie` | Response | Sends cookies from server to user-agent | + +### CORS (Cross-Origin Resource Sharing) Headers + +| Header | Type | Description | +|--------|------|-------------| +| `Access-Control-Allow-Credentials` | Response | Indicates if response can be exposed with credentials | +| `Access-Control-Allow-Headers` | Response | Lists HTTP headers usable in cross-origin requests | +| `Access-Control-Allow-Methods` | Response | Specifies allowed methods for cross-origin requests | +| `Access-Control-Allow-Origin` | Response | Indicates if response can be shared | +| `Access-Control-Expose-Headers` | Response | Lists headers exposed in cross-origin responses | +| `Access-Control-Max-Age` | Response | How long preflight request results can be cached | +| `Access-Control-Request-Headers` | Request | Lists headers used in actual request (preflight) | +| `Access-Control-Request-Method` | Request | Lists HTTP method used in actual request (preflight) | +| `Origin` | Request | Indicates where a fetch originates from | +| `Timing-Allow-Origin` | Response | Specifies origins allowed to see Resource Timing API values | + +### Message Body Information Headers + +| Header | Type | Description | +|--------|------|-------------| +| `Content-Length` | Both | Size of resource in decimal bytes | +| `Content-Type` | Both | Indicates the media type of the resource | +| `Content-Encoding` | Response | Specifies compression algorithm used | +| `Content-Language` | Response | Describes intended human language(s) | +| `Content-Location` | Response | Indicates alternate location for returned data | +| `Content-Disposition` | Response | Indicates if resource should display inline or be downloaded | + +### Range Request Headers + +| Header | Type | Description | +|--------|------|-------------| +| `Accept-Ranges` | Response | Indicates if server supports range requests | +| `Range` | Request | Indicates which part of document server should return | +| `If-Range` | Request | Creates conditional range request | +| `Content-Range` | Response | Indicates partial message position in full body | + +### Redirect Headers + +| Header | Type | Description | +|--------|------|-------------| +| `Location` | Response | Indicates URL to redirect page to | +| `Refresh` | Response | Directs browser to reload page or redirect | + +### Request Context Headers + +| Header | Type | Description | +|--------|------|-------------| +| `From` | Request | Contains email address of user controlling request | +| `Host` | Request | Specifies domain name and optional port of server | +| `Referer` | Request | Address of previous web page | +| `Referrer-Policy` | Response | Governs referrer information in Referer header | +| `User-Agent` | Request | Identifies application type and software version | + +### Response Context Headers + +| Header | Type | Description | +|--------|------|-------------| +| `Allow` | Response | Lists supported HTTP request methods | +| `Server` | Response | Contains software info for origin server | + +### Security Headers + +| Header | Type | Description | +|--------|------|-------------| +| `Cross-Origin-Embedder-Policy` (COEP) | Response | Allows server to declare embedder policy | +| `Cross-Origin-Opener-Policy` (COOP) | Response | Prevents other domains from opening/controlling window | +| `Cross-Origin-Resource-Policy` (CORP) | Response | Prevents other domains from reading response | +| `Content-Security-Policy` (CSP) | Response | Controls resources user agent can load | +| `Content-Security-Policy-Report-Only` | Response | Monitors CSP without enforcement | +| `Permissions-Policy` | Response | Allows/denies browser features in frames or iframes | +| `Strict-Transport-Security` (HSTS) | Response | Forces HTTPS communication | +| `Upgrade-Insecure-Requests` | Request | Signals preference for encrypted response | +| `X-Content-Type-Options` | Response | Disables MIME sniffing | +| `X-Frame-Options` (XFO) | Response | Indicates if page can be rendered in frame/iframe | +| `X-XSS-Protection` | Response | Enables cross-site scripting filtering | + +### Fetch Metadata Request Headers + +| Header | Type | Description | +|--------|------|-------------| +| `Sec-Fetch-Site` | Request | Relationship between initiator and target origin | +| `Sec-Fetch-Mode` | Request | Request mode (cors, navigate, no-cors, same-origin, websocket) | +| `Sec-Fetch-User` | Request | Whether navigation was triggered by user activation | +| `Sec-Fetch-Dest` | Request | Request destination (audio, document, script, style, etc.) | + +### Transfer Coding Headers + +| Header | Type | Description | +|--------|------|-------------| +| `Transfer-Encoding` | Response | Specifies encoding form for safe resource transfer | +| `TE` | Request | Specifies acceptable transfer encodings | +| `Trailer` | Response | Allows additional fields at end of chunked message | + +### WebSocket Headers + +| Header | Type | Description | +|--------|------|-------------| +| `Sec-WebSocket-Accept` | Response | Indicates willingness to upgrade to WebSocket | +| `Sec-WebSocket-Extensions` | Both | Indicates WebSocket extensions supported | +| `Sec-WebSocket-Key` | Request | Contains key verifying client intent for WebSocket | +| `Sec-WebSocket-Protocol` | Both | Indicates WebSocket sub-protocols supported | +| `Sec-WebSocket-Version` | Both | Indicates WebSocket protocol version | + +### Proxy Headers + +| Header | Type | Description | +|--------|------|-------------| +| `Forwarded` | Both | Contains information from client-facing side of proxy servers | +| `Via` | Both | Added by proxies; appears in request and response headers | +| `X-Forwarded-For` | Request | Identifies originating IP addresses through proxy (non-standard) | +| `X-Forwarded-Host` | Request | Identifies original host requested through proxy (non-standard) | +| `X-Forwarded-Proto` | Request | Identifies protocol used through proxy (non-standard) | + +### Other Notable Headers + +| Header | Type | Description | +|--------|------|-------------| +| `Alt-Svc` | Response | Lists alternate ways to reach this service | +| `Date` | Response | Date/time message originated | +| `Link` | Response | Serializes one or more links in HTTP headers | +| `Retry-After` | Response | Indicates wait time before follow-up request | +| `Server-Timing` | Response | Communicates metrics for request-response cycle | +| `Upgrade` | Request | Used to upgrade to different protocol | +| `Priority` | Both | Provides hint about resource request priority | + +--- + +## 8. HTTP Request Methods + +> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Methods> + +HTTP defines a set of request methods to indicate the purpose of the request and what is expected if successful. Each method has specific semantics and characteristics. + +### GET + +- **Purpose**: Requests a representation of the specified resource. Should only retrieve data and should not contain request content. +- **Safe**: Yes | **Idempotent**: Yes | **Cacheable**: Yes + +### HEAD + +- **Purpose**: Asks for a response identical to a GET request, but without a response body. Useful for retrieving headers only without downloading the full resource. +- **Safe**: Yes | **Idempotent**: Yes | **Cacheable**: Yes + +### POST + +- **Purpose**: Submits an entity to the specified resource, often causing a change in state or side effects on the server. Used for creating new resources and submitting data. +- **Safe**: No | **Idempotent**: No | **Cacheable**: Conditional (when responses include explicit freshness information and a matching `Content-Location` header) + +### PUT + +- **Purpose**: Replaces all current representations of the target resource with the request content. Used for updating entire resources. +- **Safe**: No | **Idempotent**: Yes | **Cacheable**: No + +### DELETE + +- **Purpose**: Deletes the specified resource. +- **Safe**: No | **Idempotent**: Yes | **Cacheable**: No + +### CONNECT + +- **Purpose**: Establishes a tunnel to the server identified by the target resource. Used for creating a tunnel for secure connections (e.g., HTTPS through a proxy). +- **Safe**: No | **Idempotent**: No | **Cacheable**: No + +### OPTIONS + +- **Purpose**: Describes the communication options for the target resource. Used for discovering allowed methods and capabilities. +- **Safe**: Yes | **Idempotent**: Yes | **Cacheable**: No + +### TRACE + +- **Purpose**: Performs a message loop-back test along the path to the target resource. Used for diagnostics and debugging. +- **Safe**: Yes | **Idempotent**: Yes | **Cacheable**: No + +### PATCH + +- **Purpose**: Applies partial modifications to a resource (unlike PUT which replaces entirely). +- **Safe**: No | **Idempotent**: No | **Cacheable**: Conditional + +### Method Characteristics Summary + +| Method | Safe | Idempotent | Cacheable | +|--------|------|------------|-----------| +| GET | Yes | Yes | Yes | +| HEAD | Yes | Yes | Yes | +| POST | No | No | Conditional | +| PUT | No | Yes | No | +| DELETE | No | Yes | No | +| CONNECT | No | No | No | +| OPTIONS | Yes | Yes | No | +| TRACE | Yes | Yes | No | +| PATCH | No | No | Conditional | + +**Safe Methods**: Methods that do not modify server state -- GET, HEAD, OPTIONS, TRACE. + +**Idempotent Methods**: Methods that produce the same result when called multiple times -- GET, HEAD, OPTIONS, TRACE, PUT, DELETE. + +**Specification**: All methods are defined in HTTP Semantics (RFC 9110). + +--- + +## 9. HTTP Response Status Codes + +> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status> + +HTTP response status codes indicate whether an HTTP request has been successfully completed. Responses are grouped into five classes based on their first digit. + +### 1xx: Informational Responses (100-199) + +| Code | Status | Description | +|------|--------|-------------| +| **100** | Continue | Interim response indicating the client should continue the request or ignore if already finished | +| **101** | Switching Protocols | Sent in response to an `Upgrade` request header; indicates the protocol the server is switching to | +| **102** | Processing | (Deprecated) Used in WebDAV contexts to indicate a request was received but no status was available | +| **103** | Early Hints | Primarily used with the `Link` header to allow the user agent to start preloading resources | + +### 2xx: Successful Responses (200-299) + +| Code | Status | Description | +|------|--------|-------------| +| **200** | OK | Request succeeded; meaning depends on HTTP method used | +| **201** | Created | Request succeeded and a new resource was created (typically after POST or PUT) | +| **202** | Accepted | Request received but not yet acted upon; intended for async or batch operations | +| **203** | Non-Authoritative Information | Returned metadata is from a local or third-party copy, not the origin server | +| **204** | No Content | No content to send, but headers may be useful; user agent may update cached headers | +| **205** | Reset Content | Tells the user agent to reset the document that sent this request | +| **206** | Partial Content | Used in response to a range request for part(s) of a resource | +| **207** | Multi-Status | (WebDAV) Conveys information about multiple resources with multiple status codes | +| **208** | Already Reported | (WebDAV) Used to avoid repeatedly enumerating internal members | +| **226** | IM Used | Server fulfilled a GET request with instance-manipulations applied | + +### 3xx: Redirection Messages (300-399) + +| Code | Status | Description | +|------|--------|-------------| +| **300** | Multiple Choices | Request has multiple possible responses; requires agent-driven content negotiation | +| **301** | Moved Permanently | URL of requested resource has been permanently changed; new URL given in response | +| **302** | Found | URI of requested resource changed temporarily; future requests should still use the same URI | +| **303** | See Other | Server directs client to get the resource at another URI using a GET request | +| **304** | Not Modified | Used for caching; tells client response has not been modified, continue using cached version | +| **307** | Temporary Redirect | Server directs client to another URI with the same HTTP method as the original request | +| **308** | Permanent Redirect | Resource is permanently at another URI; must not change the HTTP method (like 301 but stricter) | + +### 4xx: Client Error Responses (400-499) + +| Code | Status | Description | +|------|--------|-------------| +| **400** | Bad Request | Server cannot process request due to client error (malformed syntax, invalid framing) | +| **401** | Unauthorized | Client must authenticate itself to get the requested response | +| **402** | Payment Required | Originally for digital payment systems; rarely used with no standard convention | +| **403** | Forbidden | Client lacks access rights; server refuses (unlike 401, client identity is known) | +| **404** | Not Found | Server cannot find requested resource | +| **405** | Method Not Allowed | Request method known but not supported by target resource | +| **406** | Not Acceptable | Server cannot find content matching criteria given by user agent | +| **407** | Proxy Authentication Required | Similar to 401 but authentication needed by proxy | +| **408** | Request Timeout | Sent on idle connection; server wants to shut down unused connection | +| **409** | Conflict | Request conflicts with server's current state | +| **410** | Gone | Requested content permanently deleted from server with no forwarding address | +| **411** | Length Required | Server rejected request because `Content-Length` header not defined | +| **412** | Precondition Failed | Client's preconditions in headers not met by server | +| **413** | Content Too Large | Request body larger than limits defined by server | +| **414** | URI Too Long | URI requested by client longer than server willing to interpret | +| **415** | Unsupported Media Type | Media format of requested data not supported by server | +| **416** | Range Not Satisfiable | Ranges specified by `Range` header cannot be fulfilled | +| **417** | Expectation Failed | Expectation indicated by `Expect` request header cannot be met | +| **418** | I'm a teapot | Server refuses attempt to brew coffee with a teapot (April Fools' RFC 2324) | +| **421** | Misdirected Request | Request directed at server unable to produce response | +| **422** | Unprocessable Content | (WebDAV) Well-formed but unable to process due to semantic errors | +| **423** | Locked | (WebDAV) Resource being accessed is locked | +| **424** | Failed Dependency | (WebDAV) Request failed due to failure of a previous request | +| **425** | Too Early | (Experimental) Server unwilling to risk processing request that might be replayed | +| **426** | Upgrade Required | Server refuses current protocol but willing after client upgrades | +| **428** | Precondition Required | Origin server requires request to be conditional | +| **429** | Too Many Requests | User sent too many requests in given time (rate limiting) | +| **431** | Request Header Fields Too Large | Server unwilling to process because header fields too large | +| **451** | Unavailable For Legal Reasons | Resource cannot legally be provided | + +### 5xx: Server Error Responses (500-599) + +| Code | Status | Description | +|------|--------|-------------| +| **500** | Internal Server Error | Server encountered situation it does not know how to handle | +| **501** | Not Implemented | Request method not supported by server | +| **502** | Bad Gateway | Server (acting as gateway) got invalid response from upstream server | +| **503** | Service Unavailable | Server not ready to handle request (maintenance, overloaded) | +| **504** | Gateway Timeout | Server (acting as gateway) cannot get response in time | +| **505** | HTTP Version Not Supported | HTTP version used in request not supported by server | +| **506** | Variant Also Negotiates | Server has internal configuration error in content negotiation | +| **507** | Insufficient Storage | (WebDAV) Method could not be performed; server unable to store representation | +| **508** | Loop Detected | (WebDAV) Server detected infinite loop while processing request | +| **510** | Not Extended | Client request declares HTTP Extension that is not supported | +| **511** | Network Authentication Required | Client needs to authenticate to gain network access | + +**Specification**: Status codes defined by RFC 9110. + +--- + +## 10. HTTP Resources and Specifications + +> **Source:** <https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Resources_and_specifications> + +### Core HTTP Specifications + +| RFC | Title | Status | +|-----|-------|--------| +| RFC 9110 | HTTP Semantics | Internet Standard | +| RFC 9111 | HTTP Caching | Internet Standard | +| RFC 9112 | HTTP/1.1 | Internet Standard | +| RFC 9113 | HTTP/2 | Proposed Standard | +| RFC 9114 | HTTP/3 | Proposed Standard | + +### HTTP Extensions and Features + +| Resource | Title | Status | +|----------|-------|--------| +| RFC 5861 | HTTP Cache-Control Extensions for Stale Content | Informational | +| RFC 8246 | HTTP Immutable Responses | Proposed Standard | +| RFC 6265 | HTTP State Management Mechanism (Cookies) | Proposed Standard | +| RFC 2145 | Use and Interpretation of HTTP Version Numbers | Informational | +| RFC 6585 | Additional HTTP Status Codes | Proposed Standard | +| RFC 7725 | An HTTP Status Code to Report Legal Obstacles | On Standard Track | + +### Cookie-Related Specifications + +| Resource | Title | Status | +|----------|-------|--------| +| Draft Spec | Cookie Prefixes | IETF Draft | +| Draft Spec | Same-Site Cookies | IETF Draft | +| Draft Spec | Deprecate modification of 'secure' cookies from non-secure origins | IETF Draft | + +### URI and Web Linking + +| RFC | Title | Status | +|-----|-------|--------| +| RFC 2397 | The "data" URL scheme | Proposed Standard | +| RFC 3986 | Uniform Resource Identifier (URI): Generic Syntax | Internet Standard | +| RFC 5988 | Web Linking (Defines Link header) | Proposed Standard | + +### Content and Data Handling + +| RFC | Title | Status | +|-----|-------|--------| +| RFC 7578 | Returning Values from Forms: multipart/form-data | Proposed Standard | +| RFC 6266 | Use of the Content-Disposition Header Field in HTTP | Proposed Standard | +| RFC 2183 | Communicating Presentation Information: Content-Disposition Header Field | Proposed Standard | + +### Network and Protocol Extensions + +| RFC | Title | Status | +|-----|-------|--------| +| RFC 7239 | Forwarded HTTP Extension | Proposed Standard | +| RFC 6455 | The WebSocket Protocol | Proposed Standard | + +### Transport Layer Security (TLS/HTTPS) + +| RFC | Title | Status | +|-----|-------|--------| +| RFC 5246 | TLS Protocol Version 1.2 | Proposed Standard | +| RFC 8446 | TLS Protocol Version 1.3 (Supersedes 1.2) | Proposed Standard | +| RFC 2817 | Upgrading to TLS Within HTTP/1.1 | Proposed Standard | + +### HTTP/2 and HTTP/3 Support + +| RFC | Title | Status | +|-----|-------|--------| +| RFC 7541 | HPACK: Header Compression for HTTP/2 | On Standard Track | +| RFC 7838 | HTTP Alternative Services | On Standard Track | +| RFC 7301 | TLS Application-Layer Protocol Negotiation Extension | Proposed Standard | + +### Security and Privacy + +| Resource | Title | Status | +|----------|-------|--------| +| RFC 6454 | The Web Origin Concept | Proposed Standard | +| Fetch Spec | Cross-Origin Resource Sharing (CORS) | Living Standard | +| RFC 7034 | HTTP Header Field X-Frame-Options | Informational | +| RFC 6797 | HTTP Strict Transport Security (HSTS) | Proposed Standard | +| W3C Spec | Upgrade Insecure Requests | Candidate Recommendation | +| W3C Spec | Content Security Policy Level 3 | Working Draft | + +### Additional and Experimental + +| RFC | Title | Status | +|-----|-------|--------| +| RFC 5689 | HTTP Extensions for WebDAV | Proposed Standard | +| RFC 7240 | Prefer Header for HTTP | Proposed Standard | +| RFC 7486 | HTTP Origin-Bound Auth (HOBA) | Experimental | + +### Key Standards Bodies + +- **IETF** -- Internet Engineering Task Force (RFC specifications) +- **W3C** -- World Wide Web Consortium +- **WHATWG** -- Web Hypertext Application Technology Working Group +- **WICG** -- Web Incubator Community Group diff --git a/skills/create-web-form/references/javascript.md b/skills/create-web-form/references/javascript.md new file mode 100644 index 00000000..9d2f5751 --- /dev/null +++ b/skills/create-web-form/references/javascript.md @@ -0,0 +1,2413 @@ +# JavaScript Reference + +A comprehensive reference covering JavaScript fundamentals, advanced features, DOM manipulation, network requests, and modern frameworks. Consolidated from MDN Web Docs and other educational sources. + +--- + +## Table of Contents + +1. [What is JavaScript?](#what-is-javascript) +2. [Adding JavaScript to a Page](#adding-javascript-to-a-page) +3. [Script Loading Strategies](#script-loading-strategies) +4. [Comments](#comments) +5. [Variables](#variables) +6. [Numbers and Math](#numbers-and-math) +7. [Strings](#strings) +8. [Useful String Methods](#useful-string-methods) +9. [Arrays](#arrays) +10. [Conditionals](#conditionals) +11. [Loops](#loops) +12. [Functions](#functions) +13. [Building Custom Functions](#building-custom-functions) +14. [Function Return Values](#function-return-values) +15. [Events](#events) +16. [Object Basics](#object-basics) +17. [DOM Scripting](#dom-scripting) +18. [Network Requests](#network-requests) +19. [Working with JSON](#working-with-json) +20. [JavaScript Frameworks: Main Features](#javascript-frameworks-main-features) +21. [Getting Started with React](#getting-started-with-react) +22. [React Components](#react-components) + +--- + +## What is JavaScript? + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/What_is_JavaScript> + +JavaScript is a scripting or programming language that allows you to implement complex features on web pages. It enables dynamic content updates, interactive maps, animated graphics, scrolling video jukeboxes, and much more. + +### The Three Layers of Web Technologies + +JavaScript is the third layer of standard web technologies: + +- **HTML**: Markup language for structuring and giving meaning to web content +- **CSS**: Language of style rules for applying styling to HTML content +- **JavaScript**: Scripting language that creates dynamically updating content, controls multimedia, and animates images + +### What Can JavaScript Do? + +Core JavaScript features allow you to: + +- **Store useful values** in variables +- **Perform operations on text** (strings) -- combining and manipulating text +- **Run code in response to events** -- detect user interactions like clicks, keyboard input, etc. +- **Access and manipulate HTML and CSS** via the DOM (Document Object Model) + +### Practical Example + +```html +<button>Player 1: Chris</button> +``` + +```javascript +function updateName() { + const name = prompt("Enter a new name"); + button.textContent = `Player 1: ${name}`; +} + +const button = document.querySelector("button"); +button.addEventListener("click", updateName); +``` + +### Browser APIs + +Application Programming Interfaces (APIs) provide ready-made code building blocks that enable powerful functionality: + +| API | Description | +|-----|-------------| +| **DOM API** | Manipulate HTML and CSS dynamically; create, remove, and change HTML elements | +| **Geolocation API** | Retrieves geographical information | +| **Canvas and WebGL APIs** | Create animated 2D and 3D graphics | +| **Audio and Video APIs** | Play audio and video in web pages; capture video from web cameras | + +### Third-Party APIs + +Not built into browsers by default; requires grabbing code from the web: + +- **Google Maps API**: Embed custom maps into websites +- **OpenStreetMap API**: Add mapping functionality +- **Social media APIs**: Display posts on your website + +### How JavaScript Runs + +- JavaScript runs **top to bottom** in the order it appears +- Each browser tab has its own separate execution environment +- **JavaScript is interpreted** (though modern interpreters use just-in-time compiling for performance) +- **Client-side JavaScript** runs on the user's computer in the browser +- **Server-side JavaScript** runs on the server (e.g., Node.js environment) +- **Dynamic code** updates display depending on circumstances; **static code** shows the same content all the time + +--- + +## Adding JavaScript to a Page + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/What_is_JavaScript> + +### 1. Internal JavaScript + +Add JavaScript directly in your HTML file using `<script>` tags: + +```html +<body> + <button>Click me!</button> + + <script> + function createParagraph() { + const para = document.createElement("p"); + para.textContent = "You clicked the button!"; + document.body.appendChild(para); + } + + const buttons = document.querySelectorAll("button"); + for (const button of buttons) { + button.addEventListener("click", createParagraph); + } + </script> +</body> +``` + +### 2. External JavaScript (Recommended) + +Keep JavaScript in a separate file for better organization and reusability: + +**HTML file:** + +```html +<script type="module" src="script.js"></script> +``` + +**script.js file:** + +```javascript +function createParagraph() { + const para = document.createElement("p"); + para.textContent = "You clicked the button!"; + document.body.appendChild(para); +} + +const buttons = document.querySelectorAll("button"); +for (const button of buttons) { + button.addEventListener("click", createParagraph); +} +``` + +### 3. Inline JavaScript Handlers (Not Recommended) + +```html +<button onclick="createParagraph()">Click me!</button> +``` + +Avoid inline handlers because they pollute HTML with JavaScript, are inefficient, and are harder to maintain. + +### Comparison + +| Method | Location | Best For | Pros | Cons | +|--------|----------|----------|------|------| +| **Internal** | `<script>` in body | Small projects | Simple, self-contained | Not reusable | +| **External** | `<script src="">` | Most projects | Reusable, organized | Requires HTTP server | +| **Inline** | `onclick=""` | Not recommended | Quick testing | Hard to maintain, pollutes HTML | +| **Module** | `<script type="module">` | Modern projects | Safe timing, organized | Requires HTTP server | + +--- + +## Script Loading Strategies + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/What_is_JavaScript> + +### Place `<script>` at Bottom of Body + +```html +<body> + <h1>My Page</h1> + <p>Content here</p> + <script src="script.js"></script> +</body> +``` + +### Use `<script type="module">` in `<head>` (Recommended) + +```html +<head> + <script type="module" src="script.js"></script> +</head> +``` + +Browser waits for all HTML to process before executing. + +### Use `defer` Attribute + +```html +<head> + <script defer src="script.js"></script> +</head> +``` + +Script downloads in parallel while HTML continues parsing; executes only after HTML is fully parsed. Scripts with `defer` execute in order. + +### Use `async` Attribute (for non-dependent scripts) + +```html +<script async src="analytics.js"></script> +``` + +Script downloads in parallel and executes immediately when ready. Does not guarantee execution order. Use only for scripts that do not depend on DOM elements. + +### Wrap Internal Scripts in `DOMContentLoaded` + +```javascript +document.addEventListener('DOMContentLoaded', function() { + const button = document.querySelector("button"); + button.addEventListener("click", updateName); +}); +``` + +--- + +## Comments + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/What_is_JavaScript> + +### Single Line Comments + +```javascript +// This is a single line comment +const name = "Chris"; // Can also go at end of line +``` + +### Multi-Line Comments + +```javascript +/* + This is a multi-line comment. + It can span multiple lines. + Useful for longer explanations. +*/ +``` + +### Best Practices + +- Use comments to explain **why** code does something, not **what** it does +- Variable names should be intuitive -- don't comment obvious operations +- More comments are usually better than fewer, but avoid overdoing it +- Keep comments up-to-date as code changes + +--- + +## Variables + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Variables> + +A variable is a **container for a value**, like a number or string. Variables are essential because they allow your code to remember and manipulate data. + +### Declaring Variables + +Use the **`let`** keyword to create a variable: + +```javascript +let myName; +let myAge; +``` + +After declaration, the variable exists but has no value (`undefined`). + +### Initializing Variables + +Assign a value using the equals sign (`=`): + +```javascript +myName = "Chris"; +myAge = 37; +``` + +Or declare and initialize together: + +```javascript +let myDog = "Rover"; +``` + +### Variable Types + +**Numbers:** + +```javascript +let myAge = 17; // integer +let temperature = 98.6; // floating point number +``` + +**Strings:** + +```javascript +let dolphinGoodbye = "So long and thanks for all the fish"; +``` + +**Booleans:** + +```javascript +let iAmAlive = true; +let test = 6 < 3; // returns false +``` + +**Arrays:** + +```javascript +let myNameArray = ["Chris", "Bob", "Jim"]; +let myNumberArray = [10, 15, 40]; +myNameArray[0]; // "Chris" (zero-indexed) +myNumberArray[2]; // 40 +``` + +**Objects:** + +```javascript +let dog = { name: "Spot", breed: "Dalmatian" }; +dog.name; // "Spot" +``` + +### Variable Naming Rules + +- Use Latin characters (0-9, a-z, A-Z) and underscores only +- Use **lower camel case**: `myAge`, `initialColor`, `finalOutputValue` +- Make names intuitive and descriptive +- Variables are case-sensitive: `myage` is not the same as `myAge` +- Don't start with underscore or numbers +- Don't use reserved keywords (`var`, `function`, `let`, etc.) + +### Dynamic Typing + +JavaScript is **dynamically typed** -- you don't declare variable types. A variable's type is determined by the value assigned: + +```javascript +let myString = "Hello"; +typeof myString; // "string" + +let myNumber = "500"; +typeof myNumber; // "string" + +myNumber = 500; +typeof myNumber; // "number" +``` + +### Constants with `const` + +Use **`const`** for values that should not change: + +```javascript +const myDog = "Rover"; +myDog = "Fido"; // Error: cannot reassign +``` + +For objects, you can still modify properties even with `const`: + +```javascript +const bird = { species: "Kestrel" }; +bird.species = "Striated Caracara"; // OK - modifying content +``` + +### `let` vs `const` vs `var` + +| Feature | `let` | `const` | `var` | +|---------|-------|---------|-------| +| Can reassign | Yes | No | Yes | +| Must initialize | No | Yes | No | +| Scoping | Block | Block | Function | +| Hoisting issues | No | No | Yes | + +**Best Practice:** Use `const` when possible, use `let` when you need to reassign. Avoid `var` in modern JavaScript. + +--- + +## Numbers and Math + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Math> + +### Types of Numbers + +- **Integers**: Numbers without a fractional part (e.g., 10, 400, -5) +- **Floating Point Numbers (Floats)**: Have decimal points (e.g., 12.5, 56.7786543) +- JavaScript has only one data type for numbers: `Number` (plus `BigInt` for very large integers) + +### Arithmetic Operators + +| Operator | Name | Example | Result | +|----------|------|---------|--------| +| `+` | Addition | `6 + 9` | `15` | +| `-` | Subtraction | `20 - 15` | `5` | +| `*` | Multiplication | `3 * 7` | `21` | +| `/` | Division | `10 / 5` | `2` | +| `%` | Remainder (Modulo) | `8 % 3` | `2` | +| `**` | Exponent | `5 ** 2` | `25` | + +```javascript +const num1 = 10; +const num2 = 50; +9 * num1; // 90 +num1 ** 3; // 1000 +num2 / num1; // 5 +``` + +### Operator Precedence + +1. **Multiply and Divide** are done first (left to right) +2. **Add and Subtract** are done after (left to right) + +```javascript +num2 + num1 / 8 + 2; // = 53.25 (50 + 1.25 + 2) +(num2 + num1) / (8 + 2); // = 6 (60 / 10) +``` + +### Increment and Decrement Operators + +```javascript +let num1 = 4; +num1++; // Returns 4, then increments to 5 +++num1; // Increments first, then returns 6 + +let num2 = 6; +num2--; // Returns 6, then decrements to 5 +--num2; // Decrements first, then returns 4 +``` + +### Assignment Operators + +| Operator | Example | Equivalent | +|----------|---------|------------| +| `+=` | `x += 4;` | `x = x + 4;` | +| `-=` | `x -= 3;` | `x = x - 3;` | +| `*=` | `x *= 3;` | `x = x * 3;` | +| `/=` | `x /= 5;` | `x = x / 5;` | + +### Comparison Operators + +| Operator | Name | Example | Result | +|----------|------|---------|--------| +| `===` | Strict equality | `5 === 2 + 3` | `true` | +| `!==` | Strict non-equality | `5 !== 2 + 3` | `false` | +| `<` | Less than | `10 < 6` | `false` | +| `>` | Greater than | `10 > 20` | `false` | +| `<=` | Less than or equal | `3 <= 2` | `false` | +| `>=` | Greater than or equal | `5 >= 4` | `true` | + +Always use `===` and `!==` (strict versions) instead of `==` and `!=`. + +### Useful Number Methods + +```javascript +// Round to decimal places +const lotsOfDecimal = 1.7665849587; +lotsOfDecimal.toFixed(2); // "1.77" + +// Convert string to number +let myNumber = "74"; +myNumber = Number(myNumber) + 3; // 77 + +// Check data type +typeof 5; // "number" +typeof 6.667; // "number" + +// Math object methods +Math.random(); // Random number between 0 and 1 +Math.floor(2.9); // 2 (rounds down) +Math.ceil(2.1); // 3 (rounds up) +Math.pow(5, 2); // 25 (5 to the power of 2) +``` + +--- + +## Strings + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Strings> + +### Creating Strings + +Strings must be surrounded by quotes: + +```javascript +const single = 'Single quotes'; +const double = "Double quotes"; +const backtick = `Backtick`; +``` + +The same character must be used for the start and end of a string. + +### Template Literals + +Template literals (backtick-wrapped strings) have two special features: + +**1. Embedding JavaScript Expressions:** + +```javascript +const name = "Chris"; +const greeting = `Hello, ${name}`; +console.log(greeting); // "Hello, Chris" + +const song = "Fight the Youth"; +const score = 9; +const highestScore = 10; +const output = `I like the song ${song}. I gave it a score of ${ + (score / highestScore) * 100 +}%.`; +// "I like the song Fight the Youth. I gave it a score of 90%." +``` + +**2. Multiline Strings:** + +```javascript +const newline = `One day you finally knew +what you had to do, and began,`; +``` + +With regular strings, use `\n` for line breaks: + +```javascript +const newline2 = "One day you finally knew\nwhat you had to do, and began,"; +``` + +### String Concatenation + +```javascript +// Using + operator +const greeting = "Hello" + ", " + "Bob"; // "Hello, Bob" + +// Using template literals (recommended) +const name = "Ramesh"; +console.log(`Howdy, ${name}`); // "Howdy, Ramesh" +``` + +### Escaping Characters + +```javascript +const bigmouth = 'I\'ve got no right to take my place...'; +``` + +--- + +## Useful String Methods + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Useful_string_methods> + +### Finding String Length + +```javascript +const browserType = "mozilla"; +browserType.length; // 7 +``` + +### Retrieving Characters + +```javascript +browserType[0]; // "m" (first character) +browserType[browserType.length - 1]; // "a" (last character) +``` + +### Testing for Substrings + +```javascript +const browserType = "mozilla"; + +browserType.includes("zilla"); // true +browserType.startsWith("zilla"); // false +browserType.endsWith("zilla"); // true +``` + +### Finding Position of a Substring + +```javascript +const tagline = "MDN - Resources for developers, by developers"; +tagline.indexOf("developers"); // 20 +tagline.indexOf("x"); // -1 (not found) + +// Finding subsequent occurrences +const first = tagline.indexOf("developers"); // 20 +const second = tagline.indexOf("developers", first + 1); // 35 +``` + +### Extracting Substrings + +```javascript +const browserType = "mozilla"; +browserType.slice(1, 4); // "ozi" +browserType.slice(2); // "zilla" (from index 2 to end) +``` + +### Changing Case + +```javascript +const radData = "My NaMe Is MuD"; +radData.toLowerCase(); // "my name is mud" +radData.toUpperCase(); // "MY NAME IS MUD" +``` + +### Replacing Parts of a String + +```javascript +// Replace first occurrence +const browserType = "mozilla"; +const updated = browserType.replace("moz", "van"); // "vanilla" + +// Replace all occurrences +let quote = "To be or not to be"; +quote = quote.replaceAll("be", "code"); // "To code or not to code" +``` + +**Important:** String methods return new strings; they don't modify the original unless you reassign. + +--- + +## Arrays + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Arrays> + +### Creating Arrays + +```javascript +const shopping = ["bread", "milk", "cheese", "hummus", "noodles"]; +const sequence = [1, 1, 2, 3, 5, 8, 13]; +const random = ["tree", 795, [0, 1, 2]]; // Mixed types allowed +``` + +### Finding Array Length + +```javascript +shopping.length; // 5 +``` + +### Accessing and Modifying Items + +```javascript +shopping[0]; // "bread" (zero-indexed) +shopping[0] = "tahini"; // Modify first item + +// Multidimensional arrays +const random = ["tree", 795, [0, 1, 2]]; +random[2][2]; // 2 +``` + +### Finding Index of Items + +```javascript +const birds = ["Parrot", "Falcon", "Owl"]; +birds.indexOf("Owl"); // 2 +birds.indexOf("Rabbit"); // -1 (not found) +``` + +### Adding Items + +```javascript +const cities = ["Manchester", "Liverpool"]; + +// Add to end +cities.push("Cardiff"); +cities.push("Bradford", "Brighton"); // Add multiple + +// Add to start +cities.unshift("Edinburgh"); +``` + +### Removing Items + +```javascript +const cities = ["Manchester", "Liverpool", "Edinburgh", "Carlisle"]; + +// Remove from end +cities.pop(); // Returns removed item + +// Remove from start +cities.shift(); // Returns removed item + +// Remove from specific index +const index = cities.indexOf("Liverpool"); +if (index !== -1) { + cities.splice(index, 1); // Remove 1 item at index +} +cities.splice(index, 2); // Remove 2 items starting at index +``` + +### Iterating Over Arrays + +**for...of Loop:** + +```javascript +const birds = ["Parrot", "Falcon", "Owl"]; +for (const bird of birds) { + console.log(bird); +} +``` + +**map() -- Transform Items:** + +```javascript +const numbers = [5, 2, 7, 6]; +const doubled = numbers.map(number => number * 2); +// [10, 4, 14, 12] +``` + +**filter() -- Select Matching Items:** + +```javascript +const cities = ["London", "Liverpool", "Totnes", "Edinburgh"]; +const longer = cities.filter(city => city.length > 8); +// ["Liverpool", "Edinburgh"] +``` + +### Converting Between Strings and Arrays + +```javascript +// String to Array +const data = "Manchester,London,Liverpool"; +const cities = data.split(","); +// ["Manchester", "London", "Liverpool"] + +// Array to String +const commaSeparated = cities.join(","); +// "Manchester,London,Liverpool" + +// Simple toString (always uses comma) +const dogNames = ["Rocket", "Flash", "Bella"]; +dogNames.toString(); // "Rocket,Flash,Bella" +``` + +--- + +## Conditionals + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Conditionals> + +### if...else Statements + +```javascript +if (condition) { + /* code to run if condition is true */ +} else { + /* run some other code instead */ +} +``` + +### else if Statements + +```javascript +if (choice === "sunny") { + para.textContent = "Wear shorts!"; +} else if (choice === "rainy") { + para.textContent = "Take a rain coat."; +} else if (choice === "snowing") { + para.textContent = "It is freezing!"; +} else { + para.textContent = ""; +} +``` + +### Logical Operators + +**AND (`&&`) -- All conditions must be true:** + +```javascript +if (choice === "sunny" && temperature < 86) { + para.textContent = "Nice and sunny. Let's go to the beach!"; +} +``` + +**OR (`||`) -- At least one condition must be true:** + +```javascript +if (iceCreamVanOutside || houseStatus === "on fire") { + console.log("You should leave the house quickly."); +} +``` + +**NOT (`!`) -- Negates an expression:** + +```javascript +if (!(iceCreamVanOutside || houseStatus === "on fire")) { + console.log("Probably should just stay in then."); +} +``` + +**Common Mistake:** + +```javascript +// WRONG - will always evaluate to true +if (x === 5 || 7 || 10 || 20) { } + +// CORRECT +if (x === 5 || x === 7 || x === 10 || x === 20) { } +``` + +### Switch Statements + +```javascript +switch (choice) { + case "sunny": + para.textContent = "Wear shorts!"; + break; + case "rainy": + para.textContent = "Take a rain coat."; + break; + case "snowing": + para.textContent = "It is freezing!"; + break; + default: + para.textContent = ""; +} +``` + +### Ternary Operator + +```javascript +const greeting = isBirthday + ? "Happy birthday Mrs. Smith!" + : "Good morning Mrs. Smith."; +``` + +--- + +## Loops + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Loops> + +### for...of Loop + +Used to iterate through collections: + +```javascript +const cats = ["Leopard", "Serval", "Jaguar", "Tiger"]; +for (const cat of cats) { + console.log(cat); +} +``` + +### Standard for Loop + +```javascript +for (let i = 1; i < 10; i++) { + console.log(`${i} x ${i} = ${i * i}`); +} +``` + +Components: **initializer** (`let i = 1`), **condition** (`i < 10`), **final-expression** (`i++`). + +### Looping Through Arrays with for + +```javascript +const cats = ["Leopard", "Serval", "Jaguar"]; +for (let i = 0; i < cats.length; i++) { + console.log(cats[i]); +} +``` + +### while Loop + +```javascript +let i = 0; +while (i < cats.length) { + console.log(cats[i]); + i++; +} +``` + +### do...while Loop + +Code executes **at least once**, then checks condition: + +```javascript +let i = 0; +do { + console.log(cats[i]); + i++; +} while (i < cats.length); +``` + +### break and continue + +**break -- Exit Loop Immediately:** + +```javascript +for (const contact of contacts) { + const splitContact = contact.split(":"); + if (splitContact[0].toLowerCase() === searchName) { + console.log(`${splitContact[0]}'s number is ${splitContact[1]}.`); + break; + } +} +``` + +**continue -- Skip to Next Iteration:** + +```javascript +for (let i = 1; i <= num; i++) { + let sqRoot = Math.sqrt(i); + if (Math.floor(sqRoot) !== sqRoot) { + continue; // Skip non-perfect squares + } + console.log(i); +} +``` + +### Which Loop Type to Use? + +| Loop Type | Best For | +|-----------|----------| +| `for...of` | Iterating collections when you don't need index | +| `for` | General purpose loops; full control of iteration | +| `while` | When initializer before loop makes sense | +| `do...while` | When code must run at least once | +| `map()` | Transforming array items | +| `filter()` | Selecting specific array items | + +**Warning:** Always ensure loops terminate. Infinite loops crash browsers. + +--- + +## Functions + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Functions> + +### What Are Functions? + +Functions are **reusable blocks of code** that perform a single task. They allow you to store code in a defined block and call it whenever needed. + +### Built-in Browser Functions + +```javascript +const myText = "I am a string"; +const newString = myText.replace("string", "sausage"); // "I am a sausage" + +const myArray = ["I", "love", "chocolate", "frogs"]; +const madeAString = myArray.join(" "); // "I love chocolate frogs" + +const myNumber = Math.random(); // Random number between 0 and 1 +``` + +### Custom Functions + +```javascript +function myFunction() { + alert("hello"); +} + +myFunction(); // Calls the function +``` + +### Function Parameters and Default Parameters + +```javascript +function hello(name = "Chris") { + console.log(`Hello ${name}!`); +} + +hello("Ari"); // "Hello Ari!" +hello(); // "Hello Chris!" +``` + +### Anonymous Functions + +Functions without names, often passed as parameters: + +```javascript +textBox.addEventListener("keydown", function (event) { + console.log(`You pressed "${event.key}".`); +}); +``` + +### Arrow Functions + +Modern syntax using `=>`: + +```javascript +// Full syntax +textBox.addEventListener("keydown", (event) => { + console.log(`You pressed "${event.key}".`); +}); + +// Single parameter - parentheses optional +textBox.addEventListener("keydown", event => { + console.log(`You pressed "${event.key}".`); +}); + +// Single return statement - implicit return +const originals = [1, 2, 3]; +const doubled = originals.map(item => item * 2); // [2, 4, 6] +``` + +### Function Scope + +Variables inside functions are locked to **function scope** and unreachable from outside: + +```javascript +const x = 1; // global scope - accessible everywhere + +function myFunc() { + const y = 2; // function scope - only inside myFunc + console.log(x); // Can access global x +} + +console.log(x); // Can access global x +console.log(y); // ReferenceError: y is not defined +``` + +### Block Scope (let/const) + +```javascript +if (x === 1) { + const c = 4; // block scope +} +console.log(c); // ReferenceError: c is not defined +``` + +--- + +## Building Custom Functions + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Build_your_own_function> + +### Function Structure + +```javascript +function displayMessage() { + // Function body code goes here +} +``` + +Key components: + +- `function` keyword declares a function definition +- Function name follows variable naming conventions +- Parentheses `()` hold parameters +- Curly braces `{}` contain the code that runs when called + +### Complete Practical Example + +```javascript +function displayMessage(msgText, msgType) { + const body = document.body; + + const panel = document.createElement("div"); + panel.setAttribute("class", "msgBox"); + body.appendChild(panel); + + const msg = document.createElement("p"); + msg.textContent = msgText; + panel.appendChild(msg); + + const closeBtn = document.createElement("button"); + closeBtn.textContent = "x"; + panel.appendChild(closeBtn); + + closeBtn.addEventListener("click", () => body.removeChild(panel)); + + if (msgType === "warning") { + msg.style.backgroundImage = 'url("icons/warning.png")'; + panel.style.backgroundColor = "red"; + } else if (msgType === "chat") { + msg.style.backgroundImage = 'url("icons/chat.png")'; + panel.style.backgroundColor = "aqua"; + } else { + msg.style.paddingLeft = "20px"; + } +} +``` + +### Calling Functions + +```javascript +// Direct invocation +displayMessage("Your inbox is almost full", "warning"); + +// As event handler (no parentheses) +btn.addEventListener("click", displayMessage); + +// With parameters via anonymous function +btn.addEventListener("click", () => + displayMessage("Woo, this is a different message!"), +); +``` + +**Important:** Don't include parentheses when passing a function as a callback: + +```javascript +btn.addEventListener("click", displayMessage); // Correct +btn.addEventListener("click", displayMessage()); // Wrong - calls immediately +``` + +### Parameters vs Arguments + +- **Parameters** are the named variables in the function definition +- **Arguments** are the actual values passed when calling the function + +--- + +## Function Return Values + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Return_values> + +### What Are Return Values? + +Return values are the values that a function returns when it completes execution. + +```javascript +const myText = "The weather is cold"; +const newString = myText.replace("cold", "warm"); // "The weather is warm" +``` + +### Using the return Keyword + +```javascript +function random(number) { + return Math.floor(Math.random() * number); +} +``` + +When a function is called, the return value **substitutes for the function call**: + +```javascript +ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); +// If random() calls return 500, 200, 35: +ctx.arc(500, 200, 35, 0, 2 * Math.PI); +``` + +### Creating Functions with Return Values + +```javascript +function squared(num) { + return num * num; +} + +function cubed(num) { + return num * num * num; +} + +function factorial(num) { + if (num < 0) return undefined; + if (num === 0) return 1; + let x = num - 1; + while (x > 1) { + num *= x; + x--; + } + return num; +} +``` + +### Using Return Values + +```javascript +input.addEventListener("change", () => { + const num = parseFloat(input.value); + if (isNaN(num)) { + para.textContent = "You need to enter a number!"; + } else { + para.textContent = `${num} squared is ${squared(num)}. `; + para.textContent += `${num} cubed is ${cubed(num)}. `; + para.textContent += `${num} factorial is ${factorial(num)}. `; + } +}); +``` + +| Concept | Description | +|---------|-------------| +| **return keyword** | Returns a value and exits the function immediately | +| **No return value** | Functions without explicit return return `undefined` | +| **Variable storage** | Return values can be saved to variables for later use | + +--- + +## Events + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Events> + +### What Are Events? + +Events are signals fired by the browser when something significant happens. They allow your code to react to user interactions and system activities. + +### Using addEventListener() (Recommended) + +```javascript +const btn = document.querySelector("button"); + +function random(number) { + return Math.floor(Math.random() * (number + 1)); +} + +btn.addEventListener("click", () => { + const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`; + document.body.style.backgroundColor = rndCol; +}); +``` + +### Using Named Functions + +```javascript +function changeBackground() { + const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`; + document.body.style.backgroundColor = rndCol; +} + +btn.addEventListener("click", changeBackground); +``` + +### Removing Event Listeners + +```javascript +btn.removeEventListener("click", changeBackground); +``` + +### Adding Multiple Listeners + +```javascript +myElement.addEventListener("click", functionA); +myElement.addEventListener("click", functionB); +// Both functions run when element is clicked +``` + +### Common Event Types + +| Event | Description | +|-------|-------------| +| `click` | User clicks an element | +| `dblclick` | User double-clicks an element | +| `focus` | Element receives focus | +| `blur` | Element loses focus | +| `mouseover` | Mouse pointer hovers over element | +| `mouseout` | Mouse pointer leaves element | +| `keydown` | User presses a key | +| `submit` | Form is submitted | +| `play` | Media begins playing | +| `pause` | Media is paused | + +### Event Objects + +Event handler functions receive an **event object** automatically: + +```javascript +function bgChange(e) { + const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`; + e.target.style.backgroundColor = rndCol; +} + +btn.addEventListener("click", bgChange); +``` + +**Keyboard Events:** + +```javascript +const textBox = document.querySelector("#textBox"); +const output = document.querySelector("#output"); + +textBox.addEventListener("keydown", (event) => { + output.textContent = `You pressed "${event.key}".`; +}); +``` + +### Preventing Default Behavior + +```javascript +const form = document.querySelector("form"); +const fname = document.getElementById("fname"); +const lname = document.getElementById("lname"); + +form.addEventListener("submit", (e) => { + if (fname.value === "" || lname.value === "") { + e.preventDefault(); + para.textContent = "You need to fill in both names!"; + } +}); +``` + +### Event Handler Properties (Not Recommended for Multiple Handlers) + +```javascript +btn.onclick = () => { + document.body.style.backgroundColor = rndCol; +}; +``` + +Cannot add multiple listeners -- subsequent assignments overwrite previous ones. + +--- + +## Object Basics + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Object_basics> + +### What Are Objects? + +An object is a collection of related data and/or functionality, consisting of: + +- **Properties**: variables inside objects (data) +- **Methods**: functions inside objects (functionality) + +### Object Literal Syntax + +```javascript +const person = { + name: ["Bob", "Smith"], + age: 32, + bio() { + console.log(`${this.name[0]} ${this.name[1]} is ${this.age} years old.`); + }, + introduceSelf() { + console.log(`Hi! I'm ${this.name[0]}.`); + }, +}; +``` + +### Dot Notation + +```javascript +person.age; // 32 +person.bio(); // Calls the method +person.name.first; // Access nested properties +``` + +### Bracket Notation + +```javascript +person["age"]; // 32 +person["name"]["first"]; // Nested access + +// When property names are stored in variables +function logProperty(propertyName) { + console.log(person[propertyName]); +} +logProperty("name"); // ["Bob", "Smith"] +``` + +### Setting Object Members + +```javascript +// Update existing properties +person.age = 45; + +// Create new properties +person["eyes"] = "hazel"; +person.farewell = function () { + console.log("Bye everybody!"); +}; + +// Dynamic property creation (only bracket notation) +const myDataName = "height"; +const myDataValue = "1.75m"; +person[myDataName] = myDataValue; +``` + +### What is "this"? + +The `this` keyword refers to the **current object the code is being executed in**: + +```javascript +const person1 = { + name: "Chris", + introduceSelf() { + console.log(`Hi! I'm ${this.name}.`); + }, +}; + +const person2 = { + name: "Deepti", + introduceSelf() { + console.log(`Hi! I'm ${this.name}.`); + }, +}; + +person1.introduceSelf(); // "Hi! I'm Chris." +person2.introduceSelf(); // "Hi! I'm Deepti." +``` + +### Constructors + +Functions called with the `new` keyword that create new objects: + +```javascript +function Person(name) { + this.name = name; + this.introduceSelf = function () { + console.log(`Hi! I'm ${this.name}.`); + }; +} + +const salva = new Person("Salva"); +salva.introduceSelf(); // "Hi! I'm Salva." + +const frankie = new Person("Frankie"); +frankie.introduceSelf(); // "Hi! I'm Frankie." +``` + +--- + +## DOM Scripting + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/DOM_scripting> + +### What is the DOM? + +The **Document Object Model (DOM)** is a tree structure representation created by the browser that enables HTML to be accessed by programming languages. Each entry in the tree is called a **node**. + +### DOM Tree Relationships + +- **Root node**: The top node (the `HTML` element) +- **Parent node**: A node that has other nodes inside it +- **Child node**: A node directly inside another node +- **Sibling nodes**: Nodes on the same level under the same parent +- **Descendant node**: A node anywhere inside another node + +### Selecting Elements + +```javascript +// querySelector - select first match (Recommended) +const link = document.querySelector("a"); +const element = document.querySelector("#myId"); +const element = document.querySelector(".myClass"); + +// querySelectorAll - select all matches (returns NodeList) +const paragraphs = document.querySelectorAll("p"); + +// Legacy methods +const elementRef = document.getElementById('myId'); +const elementRefArray = document.getElementsByTagName('p'); +``` + +### Creating and Inserting Elements + +```javascript +const para = document.createElement("p"); +para.textContent = "We hope you enjoyed the ride."; + +const sect = document.querySelector("section"); +sect.appendChild(para); + +// Create a text node +const text = document.createTextNode(" -- the premier source."); +const linkPara = document.querySelector("p"); +linkPara.appendChild(text); +``` + +### Moving and Removing Elements + +```javascript +// Moving (appendChild on existing element moves it) +sect.appendChild(linkPara); + +// Cloning +const clone = linkPara.cloneNode(); // Shallow clone +const deepClone = linkPara.cloneNode(true); // Deep clone + +// Removing +sect.removeChild(linkPara); // Using parent +linkPara.remove(); // Modern method +linkPara.parentNode.removeChild(linkPara); // Older browsers +``` + +### Manipulating Content + +```javascript +// textContent - plain text only (safer) +link.textContent = "Mozilla Developer Network"; + +// innerHTML - parses HTML (use with caution) +element.innerHTML = "<span>New content</span>"; +``` + +### Manipulating Attributes + +```javascript +link.href = "https://developer.mozilla.org"; +element.getAttribute("class"); +element.setAttribute("class", "newClass"); +element.removeAttribute("id"); +``` + +### Manipulating Styles + +**Method 1: Inline Styles:** + +```javascript +para.style.color = "white"; +para.style.backgroundColor = "black"; +para.style.padding = "10px"; +para.style.width = "250px"; +para.style.textAlign = "center"; +``` + +Note: CSS hyphenated properties become camelCase in JavaScript (`background-color` becomes `backgroundColor`). + +**Method 2: CSS Classes (Recommended):** + +```javascript +para.classList.add("highlight"); +para.classList.remove("highlight"); +para.classList.toggle("highlight"); +``` + +### Complete Practical Example: Dynamic Shopping List + +```html +<h1>My shopping list</h1> +<form> + <label for="item">Enter a new item:</label> + <input type="text" name="item" id="item" /> + <button>Add item</button> +</form> +<ul></ul> +``` + +```javascript +const list = document.querySelector("ul"); +const input = document.querySelector("input"); +const button = document.querySelector("button"); + +button.addEventListener("click", (event) => { + event.preventDefault(); + + const myItem = input.value; + input.value = ""; + + const listItem = document.createElement("li"); + const listText = document.createElement("span"); + const listBtn = document.createElement("button"); + + listItem.appendChild(listText); + listText.textContent = myItem; + listItem.appendChild(listBtn); + listBtn.textContent = "Delete"; + list.appendChild(listItem); + + listBtn.addEventListener("click", () => { + list.removeChild(listItem); + }); + + input.focus(); +}); +``` + +### Key Browser Objects + +| Object | Description | +|--------|-------------| +| `window` | Represents the browser tab | +| `document` | The page loaded in the window | +| `navigator` | Browser state and identity | + +--- + +## Network Requests + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Network_requests> + +### The Fetch API + +The main modern JavaScript API for making HTTP requests to retrieve resources from the server without full page reloads. + +### Basic Syntax + +```javascript +fetch(url) + .then((response) => { + if (!response.ok) { + throw new Error(`HTTP error: ${response.status}`); + } + return response.text(); + }) + .then((data) => { + // Use the data + }) + .catch((error) => { + console.error(`Fetch problem: ${error.message}`); + }); +``` + +### Fetching Text Content + +```javascript +function updateDisplay(verse) { + verse = verse.replace(" ", "").toLowerCase(); + const url = `${verse}.txt`; + + fetch(url) + .then((response) => { + if (!response.ok) { + throw new Error(`HTTP error: ${response.status}`); + } + return response.text(); + }) + .then((text) => { + poemDisplay.textContent = text; + }) + .catch((error) => { + poemDisplay.textContent = `Could not fetch verse: ${error}`; + }); +} +``` + +### Fetching JSON Data + +```javascript +fetch("products.json") + .then((response) => { + if (!response.ok) { + throw new Error(`HTTP error: ${response.status}`); + } + return response.json(); + }) + .then((json) => initialize(json)) + .catch((err) => console.error(`Fetch problem: ${err.message}`)); +``` + +### Fetching Binary Data (Blob) + +```javascript +fetch(url) + .then((response) => { + if (!response.ok) { + throw new Error(`HTTP error: ${response.status}`); + } + return response.blob(); + }) + .then((blob) => showProduct(blob, product)) + .catch((err) => console.error(`Fetch problem: ${err.message}`)); +``` + +### Core Response Methods + +| Method | Use Case | +|--------|----------| +| `response.text()` | Plain text files | +| `response.json()` | JSON objects/arrays | +| `response.blob()` | Binary data (images, videos) | + +### Error Handling + +```javascript +.then((response) => { + if (!response.ok) { + throw new Error(`HTTP error: ${response.status}`); + } + return response.json(); +}) +.catch((error) => { + console.error(`Fetch problem: ${error.message}`); +}); +``` + +**Important**: `fetch()` only rejects on network failures, not HTTP error statuses (404, 500). Always check `response.ok` or `response.status`. + +### XMLHttpRequest (Legacy Alternative) + +```javascript +const request = new XMLHttpRequest(); + +try { + request.open("GET", "products.json"); + request.responseType = "json"; + + request.addEventListener("load", () => { + initialize(request.response); + }); + request.addEventListener("error", () => { + console.error("XHR error"); + }); + + request.send(); +} catch (error) { + console.error(`XHR error ${request.status}`); +} +``` + +Fetch is simpler and recommended over XMLHttpRequest. + +--- + +## Working with JSON + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/JSON> + +### What is JSON? + +**JSON (JavaScript Object Notation)** is a standard text-based format for representing structured data based on JavaScript object syntax, commonly used for transmitting data in web applications. + +- Converting a string to a native object is called **deserialization** +- Converting a native object to a string is called **serialization** +- JSON files use the `.json` extension and `application/json` MIME type + +### JSON Structure + +```json +{ + "squadName": "Super hero squad", + "homeTown": "Metro City", + "formed": 2016, + "secretBase": "Super tower", + "active": true, + "members": [ + { + "name": "Molecule Man", + "age": 29, + "secretIdentity": "Dan Jukes", + "powers": ["Radiation resistance", "Turning tiny", "Radiation blast"] + } + ] +} +``` + +### Valid JSON Data Types + +- String literals, number literals, `true`, `false`, `null` +- Objects and arrays containing valid JSON types + +**Not valid in JSON:** + +- `undefined`, `NaN`, `Infinity` +- Functions or object types like `Date`, `Set`, `Map` +- Single quotes (must use double quotes) +- Trailing commas +- Comments + +### Accessing JSON Data + +```javascript +superHeroes.homeTown; // "Metro City" +superHeroes.members[1].powers[2]; // Third power of second hero +superHeroes[0].powers[0]; // For top-level arrays +``` + +### JSON.parse() -- String to Object + +```javascript +const jsonString = '{"name":"John","age":30}'; +const obj = JSON.parse(jsonString); +console.log(obj.name); // "John" +``` + +### JSON.stringify() -- Object to String + +```javascript +let myObj = { name: "Chris", age: 38 }; +let myString = JSON.stringify(myObj); +console.log(myString); // '{"name":"Chris","age":38}' +``` + +### Complete Example: Fetching and Displaying JSON + +```javascript +async function populate() { + const requestURL = + "https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json"; + const request = new Request(requestURL); + + const response = await fetch(request); + const superHeroes = await response.json(); + + populateHeader(superHeroes); + populateHeroes(superHeroes); +} + +function populateHeader(obj) { + const header = document.querySelector("header"); + const myH1 = document.createElement("h1"); + myH1.textContent = obj.squadName; + header.appendChild(myH1); + + const myPara = document.createElement("p"); + myPara.textContent = `Hometown: ${obj.homeTown} // Formed: ${obj.formed}`; + header.appendChild(myPara); +} + +function populateHeroes(obj) { + const section = document.querySelector("section"); + const heroes = obj.members; + + for (const hero of heroes) { + const myArticle = document.createElement("article"); + const myH2 = document.createElement("h2"); + myH2.textContent = hero.name; + myArticle.appendChild(myH2); + + const myPara = document.createElement("p"); + myPara.textContent = `Secret identity: ${hero.secretIdentity}`; + myArticle.appendChild(myPara); + + section.appendChild(myArticle); + } +} + +populate(); +``` + +--- + +## JavaScript Frameworks: Main Features + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Main_features> + +### Domain-Specific Languages (DSLs) + +**JSX (JavaScript and XML):** + +```jsx +const subject = "World"; +const header = ( + <header> + <h1>Hello, {subject}!</h1> + </header> +); +``` + +Compiles to: + +```javascript +const header = React.createElement( + "header", + null, + React.createElement("h1", null, "Hello, ", subject, "!"), +); +``` + +**Handlebars (Ember):** + +```handlebars +<header> + <h1>Hello, {{subject}}!</h1> +</header> +``` + +**TypeScript (Angular):** + +```typescript +function add(a: number, b: number) { + return a + b; +} +``` + +### Component Props and State + +**Props (External Data):** + +```jsx +function AuthorCredit(props) { + return ( + <figure> + <img src={props.src} alt={props.alt} /> + <figcaption>{props.byline}</figcaption> + </figure> + ); +} + +<AuthorCredit + src="./assets/zelda.png" + alt="Portrait of Zelda Schiff" + byline="Zelda Schiff is editor-in-chief of the Library Times." +/> +``` + +**State (Internal Data):** + +```jsx +function CounterButton() { + const [count, setCount] = useState(0); + return ( + <button onClick={() => setCount(count + 1)}> + Clicked {count} times + </button> + ); +} +``` + +### Rendering Approaches + +| Approach | Used By | Description | +|----------|---------|-------------| +| **Virtual DOM** | React, Vue | Stores DOM info in JS memory, diffs with real DOM, applies changes | +| **Incremental DOM** | Angular | Doesn't create complete copy, ignores unchanged parts | +| **Glimmer VM** | Ember | Transpiles templates into bytecode | + +### Dependency Injection + +Solutions to "prop drilling" (passing data through many nesting levels): + +- **Angular**: Dependency injection system +- **Vue**: `provide()` and `inject()` methods +- **React**: Context API +- **Ember**: Services + +### Testing Example (React Testing Library) + +```jsx +import { fireEvent, render, screen } from "@testing-library/react"; +import CounterButton from "./CounterButton"; + +it("Renders a semantic button with an initial state of 0", () => { + render(<CounterButton />); + const btn = screen.getByRole("button"); + expect(btn).toBeInTheDocument(); + expect(btn).toHaveTextContent("Clicked 0 times"); +}); + +it("Increments the count when clicked", () => { + render(<CounterButton />); + const btn = screen.getByRole("button"); + fireEvent.click(btn); + expect(btn).toHaveTextContent("Clicked 1 times"); +}); +``` + +--- + +## Getting Started with React + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_getting_started> + +### What is React? + +React is **a library for building user interfaces**. It is not a framework -- it is a reusable library used with other libraries like ReactDOM for web development. Its primary goal is to minimize bugs when building UIs through the use of **components**. + +### Environment Setup + +Requirements: + +- **Node.js** (v18 or later; v20 LTS recommended) +- **npm** (comes with Node.js) + +### Creating a React App with Vite + +```bash +npm create vite@latest moz-todo-react -- --template react +cd moz-todo-react && npm install +npm run dev -- --open --port 3000 +``` + +### Project Structure + +``` +moz-todo-react/ + index.html (Entry HTML file) + package.json (Project metadata & dependencies) + src/ + App.jsx (Main component) + App.css + main.jsx (Entry point - imports App) + index.css (Global styles) + assets/ + vite.config.js +``` + +### Understanding JSX + +JSX extends JavaScript to allow HTML-like code alongside JavaScript: + +```jsx +const heading = <h1>Mozilla Developer Network</h1>; +``` + +Attributes use `className` instead of `class`: + +```jsx +<button type="button" className="primary"> + Click me! +</button> +``` + +### Basic Component + +```jsx +import "./App.css"; + +function App() { + return ( + <> + <header> + <h1>Hello, World!</h1> + <button type="button">Click me!</button> + </header> + </> + ); +} + +export default App; +``` + +### Fragments + +Use `<>` (fragments) to return multiple elements without extra `<div>` wrappers: + +```jsx +return ( + <> + <header>Content</header> + <main>More content</main> + </> +); +``` + +### JavaScript Expressions in JSX + +Use curly braces `{}` to embed JavaScript expressions: + +```jsx +const subject = "React"; + +function App() { + return ( + <> + <h1>Hello, {subject}!</h1> + <h1>Hello, {subject.toUpperCase()}!</h1> + <h1>Hello, {2 + 2}!</h1> + </> + ); +} +``` + +### Props (Component Properties) + +Props pass data from parent to child components (unidirectional data flow): + +```jsx +// main.jsx +<App subject="Clarice" /> + +// App.jsx +function App(props) { + return ( + <header> + <h1>Hello, {props.subject}!</h1> + </header> + ); +} +``` + +### Rendering the App + +```jsx +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import App from "./App.jsx"; + +createRoot(document.getElementById("root")).render( + <StrictMode> + <App subject="Clarice" /> + </StrictMode> +); +``` + +--- + +## React Components + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_components> + +### Creating Components + +A functional component is a JavaScript function that returns JSX: + +```jsx +function Todo(props) { + return ( + <li className="todo stack-small"> + <div className="c-cb"> + <input id={props.id} type="checkbox" defaultChecked={props.completed} /> + <label className="todo-label" htmlFor={props.id}> + {props.name} + </label> + </div> + <div className="btn-group"> + <button type="button" className="btn"> + Edit <span className="visually-hidden">{props.name}</span> + </button> + <button type="button" className="btn btn__danger"> + Delete <span className="visually-hidden">{props.name}</span> + </button> + </div> + </li> + ); +} + +export default Todo; +``` + +### Passing Props + +```jsx +<ul role="list" className="todo-list"> + <Todo name="Eat" id="todo-0" completed /> + <Todo name="Sleep" id="todo-1" /> + <Todo name="Repeat" id="todo-2" /> +</ul> +``` + +### Rendering Lists with map() + +```jsx +const DATA = [ + { id: "todo-0", name: "Eat", completed: true }, + { id: "todo-1", name: "Sleep", completed: false }, + { id: "todo-2", name: "Repeat", completed: false }, +]; + +function App(props) { + const taskList = props.tasks?.map((task) => ( + <Todo + id={task.id} + name={task.name} + completed={task.completed} + key={task.id} + /> + )); + + return ( + <ul + role="list" + className="todo-list stack-large stack-exception" + aria-labelledby="list-heading"> + {taskList} + </ul> + ); +} +``` + +### Unique Keys + +Always provide a unique `key` prop to items rendered with iteration: + +```jsx +const taskList = props.tasks?.map((task) => ( + <Todo + id={task.id} + name={task.name} + completed={task.completed} + key={task.id} + /> +)); +``` + +React uses keys to track which items have changed, been added, or removed. + +### Component Architecture Example + +```jsx +// src/components/Form.jsx +function Form() { + return ( + <form> + <h2 className="label-wrapper"> + <label htmlFor="new-todo-input" className="label__lg"> + What needs to be done? + </label> + </h2> + <input + type="text" + id="new-todo-input" + className="input input__lg" + name="text" + autoComplete="off" + /> + <button type="submit" className="btn btn__primary btn__lg"> + Add + </button> + </form> + ); +} + +export default Form; +``` + +```jsx +// src/App.jsx +import Form from "./components/Form"; +import FilterButton from "./components/FilterButton"; +import Todo from "./components/Todo"; + +function App(props) { + const taskList = props.tasks?.map((task) => ( + <Todo + id={task.id} + name={task.name} + completed={task.completed} + key={task.id} + /> + )); + + return ( + <div className="todoapp stack-large"> + <h1>TodoMatic</h1> + <Form /> + <div className="filters btn-group stack-exception"> + <FilterButton /> + <FilterButton /> + <FilterButton /> + </div> + <h2 id="list-heading">3 tasks remaining</h2> + <ul + role="list" + className="todo-list stack-large stack-exception" + aria-labelledby="list-heading"> + {taskList} + </ul> + </div> + ); +} + +export default App; +``` + +--- + +## A First Splash into JavaScript + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/A_first_splash> + +### Thinking Like a Programmer + +Programming requires breaking problems into actionable tasks, applying syntax to real-world problems, and understanding how features work together. + +### Number Guessing Game: Complete Example + +```javascript +let randomNumber = Math.floor(Math.random() * 100) + 1; + +const guesses = document.querySelector(".guesses"); +const lastResult = document.querySelector(".lastResult"); +const lowOrHi = document.querySelector(".lowOrHi"); +const guessSubmit = document.querySelector(".guessSubmit"); +const guessField = document.querySelector(".guessField"); + +let guessCount = 1; +let resetButton; + +function checkGuess() { + const userGuess = Number(guessField.value); + + if (guessCount === 1) { + guesses.textContent = "Previous guesses:"; + } + guesses.textContent = `${guesses.textContent} ${userGuess}`; + + if (userGuess === randomNumber) { + lastResult.textContent = "Congratulations! You got it right!"; + lastResult.style.backgroundColor = "green"; + lowOrHi.textContent = ""; + setGameOver(); + } else if (guessCount === 10) { + lastResult.textContent = "!!!GAME OVER!!!"; + lowOrHi.textContent = ""; + setGameOver(); + } else { + lastResult.textContent = "Wrong!"; + lastResult.style.backgroundColor = "red"; + if (userGuess < randomNumber) { + lowOrHi.textContent = "Last guess was too low!"; + } else if (userGuess > randomNumber) { + lowOrHi.textContent = "Last guess was too high!"; + } + } + + guessCount++; + guessField.value = ""; + guessField.focus(); +} + +guessSubmit.addEventListener("click", checkGuess); + +function setGameOver() { + guessField.disabled = true; + guessSubmit.disabled = true; + resetButton = document.createElement("button"); + resetButton.textContent = "Start new game"; + document.body.appendChild(resetButton); + resetButton.addEventListener("click", resetGame); +} + +function resetGame() { + guessCount = 1; + + const resetParas = document.querySelectorAll(".resultParas p"); + for (const resetPara of resetParas) { + resetPara.textContent = ""; + } + + resetButton.parentNode.removeChild(resetButton); + + guessField.disabled = false; + guessSubmit.disabled = false; + guessField.value = ""; + guessField.focus(); + + lastResult.style.backgroundColor = "white"; + + randomNumber = Math.floor(Math.random() * 100) + 1; +} +``` + +### Key Techniques Demonstrated + +- `Math.floor(Math.random() * 100) + 1` -- generate random integer +- `Number()` constructor -- convert input to a number +- `document.querySelector()` -- select DOM elements +- `.textContent` -- set text in elements +- `.style.backgroundColor` -- change element styling +- `.disabled` -- disable/enable form elements +- `document.createElement()` -- create new HTML elements +- `.appendChild()` / `.removeChild()` -- add/remove elements from DOM +- `addEventListener()` -- attach event listeners +- `.focus()` -- return focus to input field + +--- + +## JavaScript Learning Module Overview + +> Source: <https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting> + +### Topics Covered in the MDN Learning Path + +**Core Language Fundamentals:** + +1. What is JavaScript? +2. A first splash into JavaScript +3. Troubleshooting JavaScript +4. Variables +5. Numbers and operators +6. Strings +7. Useful string methods +8. Arrays + +**Control Flow and Functions:** +9. Conditionals +10. Loops +11. Functions +12. Build your own function +13. Function return values + +**Events and DOM Manipulation:** +14. Introduction to events +15. Event bubbling +16. Object basics +17. DOM scripting + +**APIs and Data:** +18. Making network requests +19. Working with JSON + +**Error Handling:** +20. JavaScript debugging and error handling + +### Practical Challenges + +- **Silly story generator** -- Variables, math, strings, arrays +- **Image gallery** -- Loops, functions, conditionals, events +- **House data UI** -- JSON fetching, filtering, rendering + +--- + +## JavaScript Built-in Objects Quick Reference + +> Source: <https://www.w3schools.com/jsref/jsref_reference.asp> (partial -- access was restricted) + +### Core Objects and Common Methods + +**Array Methods:** +`concat()`, `every()`, `filter()`, `find()`, `findIndex()`, `forEach()`, `from()`, `includes()`, `indexOf()`, `isArray()`, `join()`, `keys()`, `lastIndexOf()`, `map()`, `of()`, `pop()`, `push()`, `reduce()`, `reduceRight()`, `reverse()`, `shift()`, `slice()`, `some()`, `sort()`, `splice()`, `toString()`, `unshift()`, `values()` + +**String Methods:** +`charAt()`, `charCodeAt()`, `concat()`, `endsWith()`, `fromCharCode()`, `includes()`, `indexOf()`, `lastIndexOf()`, `match()`, `matchAll()`, `padEnd()`, `padStart()`, `repeat()`, `replace()`, `replaceAll()`, `search()`, `slice()`, `split()`, `startsWith()`, `substring()`, `toLowerCase()`, `toUpperCase()`, `trim()`, `trimEnd()`, `trimStart()` + +**Number Methods:** +`isFinite()`, `isInteger()`, `isNaN()`, `isSafeInteger()`, `parseFloat()`, `parseInt()`, `toExponential()`, `toFixed()`, `toLocaleString()`, `toPrecision()`, `toString()` + +**Math Methods:** +`abs()`, `acos()`, `asin()`, `atan()`, `atan2()`, `cbrt()`, `ceil()`, `cos()`, `exp()`, `floor()`, `log()`, `max()`, `min()`, `pow()`, `random()`, `round()`, `sign()`, `sin()`, `sqrt()`, `tan()`, `trunc()` + +**Date Methods:** +`getDate()`, `getDay()`, `getFullYear()`, `getHours()`, `getMilliseconds()`, `getMinutes()`, `getMonth()`, `getSeconds()`, `getTime()`, `now()`, `parse()`, `setDate()`, `setFullYear()`, `setHours()`, `setMilliseconds()`, `setMinutes()`, `setMonth()`, `setSeconds()`, `toDateString()`, `toISOString()`, `toJSON()`, `toLocaleDateString()`, `toLocaleString()`, `toLocaleTimeString()`, `toString()`, `toTimeString()`, `toUTCString()` + +**JSON Methods:** +`JSON.parse()`, `JSON.stringify()` + +**Global Functions:** +`decodeURI()`, `decodeURIComponent()`, `encodeURI()`, `encodeURIComponent()`, `eval()`, `isFinite()`, `isNaN()`, `Number()`, `parseFloat()`, `parseInt()`, `String()` + +**Promise Methods:** +`Promise.all()`, `Promise.allSettled()`, `Promise.any()`, `Promise.race()`, `Promise.reject()`, `Promise.resolve()`, `.then()`, `.catch()`, `.finally()` + +--- + +*This reference was compiled from the following sources:* + +1. *<https://www.w3schools.com/jsref/jsref_reference.asp>* +2. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting>* +3. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/What_is_JavaScript>* +4. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/A_first_splash>* +5. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Variables>* +6. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Math>* +7. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Strings>* +8. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Useful_string_methods>* +9. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Arrays>* +10. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Conditionals>* +11. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Loops>* +12. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Functions>* +13. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Build_your_own_function>* +14. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Return_values>* +15. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Events>* +16. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Object_basics>* +17. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_components>* +18. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_getting_started>* +19. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Main_features>* +20. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/DOM_scripting>* +21. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Network_requests>* +22. *<https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/JSON>* diff --git a/skills/create-web-form/references/php-cookies.md b/skills/create-web-form/references/php-cookies.md new file mode 100644 index 00000000..3408527c --- /dev/null +++ b/skills/create-web-form/references/php-cookies.md @@ -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> +``` diff --git a/skills/create-web-form/references/php-forms.md b/skills/create-web-form/references/php-forms.md new file mode 100644 index 00000000..f0545be3 --- /dev/null +++ b/skills/create-web-form/references/php-forms.md @@ -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. diff --git a/skills/create-web-form/references/php-json.md b/skills/create-web-form/references/php-json.md new file mode 100644 index 00000000..58e5dedb --- /dev/null +++ b/skills/create-web-form/references/php-json.md @@ -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 +``` diff --git a/skills/create-web-form/references/php-mysql-database.md b/skills/create-web-form/references/php-mysql-database.md new file mode 100644 index 00000000..ba88c693 --- /dev/null +++ b/skills/create-web-form/references/php-mysql-database.md @@ -0,0 +1,1696 @@ +# PHP MySQL Database Reference + +A consolidated reference for working with MySQL databases in PHP, covering connections, +CRUD operations, prepared statements, and query techniques. + +--- + +## Table of Contents + +1. [MySQL Introduction](#1-mysql-introduction) +2. [Connect to MySQL](#2-connect-to-mysql) +3. [Create a Database](#3-create-a-database) +4. [Create a Table](#4-create-a-table) +5. [Insert Data](#5-insert-data) +6. [Get Last Inserted ID](#6-get-last-inserted-id) +7. [Insert Multiple Records](#7-insert-multiple-records) +8. [Prepared Statements](#8-prepared-statements) +9. [Select Data](#9-select-data) +10. [Select with WHERE](#10-select-with-where) +11. [Select with ORDER BY](#11-select-with-order-by) +12. [Delete Data](#12-delete-data) +13. [Update Data](#13-update-data) +14. [Select with LIMIT](#14-select-with-limit) + +--- + +## 1. MySQL Introduction + +> **Source:** <https://www.w3schools.com/php/php_mysql_intro.asp> + +### What is MySQL? + +MySQL is the most popular open-source relational database management system. Together with PHP, +MySQL is used to create dynamic, data-driven web applications. + +### Key Points + +- **MySQL** is a database system used on the web. +- **MySQL** runs on a server (typically alongside a web server such as Apache). +- It is ideal for both small and large applications. +- It is very fast, reliable, and easy to use. +- It uses standard **SQL** (Structured Query Language). +- It is free to download and use. +- MySQL is developed, distributed, and supported by Oracle Corporation. + +### Data in MySQL + +- Data in MySQL is stored in **tables**. +- A table is a collection of related data consisting of **columns** and **rows**. +- Databases are useful for storing information categorically. For example, a company may have + databases for Employees, Products, and Customers. + +### PHP + MySQL Database System + +- PHP combined with MySQL is cross-platform (runs on Windows, Linux, macOS, etc.). +- The PHP code for querying a MySQL database is executed on the server, and the HTML result + is sent to the browser. + +### PHP MySQL APIs + +PHP offers three ways to connect to and interact with MySQL: + +| API | Description | +|-----|-------------| +| **MySQLi (Object-Oriented)** | MySQL Improved extension - OO interface | +| **MySQLi (Procedural)** | MySQL Improved extension - procedural interface | +| **PDO (PHP Data Objects)** | Works with 12 different database systems | + +**Recommendation:** Use **MySQLi** or **PDO**. The older `mysql_*` functions are deprecated and +removed as of PHP 7.0. + +**MySQLi vs PDO:** + +- **PDO** works on 12 different database systems; **MySQLi** only works with MySQL. +- If you need to switch your project to another database, PDO makes the process easier -- you + only have to change the connection string and a few queries. +- Both support **Prepared Statements**, which protect against SQL injection. + +--- + +## 2. Connect to MySQL + +> **Source:** <https://www.w3schools.com/php/php_mysql_connect.asp> + +### Open a Connection to MySQL + +Before accessing data in the MySQL database, you need to connect to the server. + +### MySQLi Object-Oriented Connection + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; + +// Create connection +$conn = new mysqli($servername, $username, $password); + +// Check connection +if ($conn->connect_error) { + die("Connection failed: " . $conn->connect_error); +} +echo "Connected successfully"; +?> +``` + +### MySQLi Procedural Connection + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; + +// Create connection +$conn = mysqli_connect($servername, $username, $password); + +// Check connection +if (!$conn) { + die("Connection failed: " . mysqli_connect_error()); +} +echo "Connected successfully"; +?> +``` + +### PDO Connection + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; + +try { + $conn = new PDO("mysql:host=$servername;dbname=myDB", $username, $password); + // Set the PDO error mode to exception + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + echo "Connected successfully"; +} catch(PDOException $e) { + echo "Connection failed: " . $e->getMessage(); +} +?> +``` + +**Note:** In the PDO example, a database (`myDB`) is specified. PDO requires a valid database +to connect to. If no database is specified, an exception is thrown. + +### Closing the Connection + +The connection is automatically closed when the script ends. To close it before that: + +```php +// MySQLi Object-Oriented +$conn->close(); + +// MySQLi Procedural +mysqli_close($conn); + +// PDO +$conn = null; +``` + +--- + +## 3. Create a Database + +> **Source:** <https://www.w3schools.com/php/php_mysql_create.asp> + +The `CREATE DATABASE` statement is used to create a database in MySQL. + +### MySQLi Object-Oriented + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; + +// Create connection +$conn = new mysqli($servername, $username, $password); + +// Check connection +if ($conn->connect_error) { + die("Connection failed: " . $conn->connect_error); +} + +// Create database +$sql = "CREATE DATABASE myDB"; +if ($conn->query($sql) === TRUE) { + echo "Database created successfully"; +} else { + echo "Error creating database: " . $conn->error; +} + +$conn->close(); +?> +``` + +### MySQLi Procedural + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; + +// Create connection +$conn = mysqli_connect($servername, $username, $password); + +// Check connection +if (!$conn) { + die("Connection failed: " . mysqli_connect_error()); +} + +// Create database +$sql = "CREATE DATABASE myDB"; +if (mysqli_query($conn, $sql)) { + echo "Database created successfully"; +} else { + echo "Error creating database: " . mysqli_error($conn); +} + +mysqli_close($conn); +?> +``` + +### PDO + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; + +try { + $conn = new PDO("mysql:host=$servername", $username, $password); + // Set the PDO error mode to exception + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $sql = "CREATE DATABASE myDBPDO"; + // Use exec() because no results are returned + $conn->exec($sql); + echo "Database created successfully<br>"; +} catch(PDOException $e) { + echo $sql . "<br>" . $e->getMessage(); +} + +$conn = null; +?> +``` + +**Tip:** When creating a database, you only need to specify the first three arguments to the +`mysqli` object (servername, username, and password). To select a specific database, add a +fourth argument. + +--- + +## 4. Create a Table + +> **Source:** <https://www.w3schools.com/php/php_mysql_create_table.asp> + +The `CREATE TABLE` statement is used to create a table in MySQL. + +### Key SQL Concepts for Table Creation + +- **NOT NULL** - Each row must contain a value for that column; null values are not allowed. +- **DEFAULT value** - Set a default value that is added when no other value is passed. +- **UNSIGNED** - Used for number types, limits the stored data to positive numbers and zero. +- **AUTO_INCREMENT** - MySQL automatically increases the value of the field by 1 each time a + new record is added. +- **PRIMARY KEY** - Used to uniquely identify the rows in a table. The column with PRIMARY KEY + setting is often an ID number and is used with `AUTO_INCREMENT`. + +### MySQLi Object-Oriented + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = new mysqli($servername, $username, $password, $dbname); + +// Check connection +if ($conn->connect_error) { + die("Connection failed: " . $conn->connect_error); +} + +// SQL to create table +$sql = "CREATE TABLE MyGuests ( + id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY, + firstname VARCHAR(30) NOT NULL, + lastname VARCHAR(30) NOT NULL, + email VARCHAR(50), + reg_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +)"; + +if ($conn->query($sql) === TRUE) { + echo "Table MyGuests created successfully"; +} else { + echo "Error creating table: " . $conn->error; +} + +$conn->close(); +?> +``` + +### MySQLi Procedural + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = mysqli_connect($servername, $username, $password, $dbname); + +// Check connection +if (!$conn) { + die("Connection failed: " . mysqli_connect_error()); +} + +// SQL to create table +$sql = "CREATE TABLE MyGuests ( + id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY, + firstname VARCHAR(30) NOT NULL, + lastname VARCHAR(30) NOT NULL, + email VARCHAR(50), + reg_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +)"; + +if (mysqli_query($conn, $sql)) { + echo "Table MyGuests created successfully"; +} else { + echo "Error creating table: " . mysqli_error($conn); +} + +mysqli_close($conn); +?> +``` + +### PDO + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDBPDO"; + +try { + $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password); + // Set the PDO error mode to exception + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + // SQL to create table + $sql = "CREATE TABLE MyGuests ( + id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY, + firstname VARCHAR(30) NOT NULL, + lastname VARCHAR(30) NOT NULL, + email VARCHAR(50), + reg_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP + )"; + + // Use exec() because no results are returned + $conn->exec($sql); + echo "Table MyGuests created successfully"; +} catch(PDOException $e) { + echo $sql . "<br>" . $e->getMessage(); +} + +$conn = null; +?> +``` + +--- + +## 5. Insert Data + +> **Source:** <https://www.w3schools.com/php/php_mysql_insert.asp> + +The `INSERT INTO` statement is used to add new records to a MySQL table. + +### SQL Syntax + +```sql +INSERT INTO table_name (column1, column2, column3, ...) +VALUES (value1, value2, value3, ...) +``` + +**Important rules:** + +- SQL queries must be quoted in PHP. +- String values inside the SQL query must be quoted. +- Numeric values must NOT be quoted. +- The word NULL must NOT be quoted. + +### MySQLi Object-Oriented + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = new mysqli($servername, $username, $password, $dbname); + +// Check connection +if ($conn->connect_error) { + die("Connection failed: " . $conn->connect_error); +} + +$sql = "INSERT INTO MyGuests (firstname, lastname, email) +VALUES ('John', 'Doe', 'john@example.com')"; + +if ($conn->query($sql) === TRUE) { + echo "New record created successfully"; +} else { + echo "Error: " . $sql . "<br>" . $conn->error; +} + +$conn->close(); +?> +``` + +### MySQLi Procedural + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = mysqli_connect($servername, $username, $password, $dbname); + +// Check connection +if (!$conn) { + die("Connection failed: " . mysqli_connect_error()); +} + +$sql = "INSERT INTO MyGuests (firstname, lastname, email) +VALUES ('John', 'Doe', 'john@example.com')"; + +if (mysqli_query($conn, $sql)) { + echo "New record created successfully"; +} else { + echo "Error: " . $sql . "<br>" . mysqli_error($conn); +} + +mysqli_close($conn); +?> +``` + +### PDO + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDBPDO"; + +try { + $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password); + // Set the PDO error mode to exception + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $sql = "INSERT INTO MyGuests (firstname, lastname, email) + VALUES ('John', 'Doe', 'john@example.com')"; + // Use exec() because no results are returned + $conn->exec($sql); + echo "New record created successfully"; +} catch(PDOException $e) { + echo $sql . "<br>" . $e->getMessage(); +} + +$conn = null; +?> +``` + +**Note:** The `id` column and `reg_date` column do not need values specified, as `id` is +`AUTO_INCREMENT` and `reg_date` has a default of `CURRENT_TIMESTAMP`. + +--- + +## 6. Get Last Inserted ID + +> **Source:** <https://www.w3schools.com/php/php_mysql_insert_lastid.asp> + +If you perform an INSERT on a table with an AUTO_INCREMENT column, you can retrieve the ID of +the last inserted row immediately. + +### MySQLi Object-Oriented + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = new mysqli($servername, $username, $password, $dbname); + +// Check connection +if ($conn->connect_error) { + die("Connection failed: " . $conn->connect_error); +} + +$sql = "INSERT INTO MyGuests (firstname, lastname, email) +VALUES ('John', 'Doe', 'john@example.com')"; + +if ($conn->query($sql) === TRUE) { + $last_id = $conn->insert_id; + echo "New record created successfully. Last inserted ID is: " . $last_id; +} else { + echo "Error: " . $sql . "<br>" . $conn->error; +} + +$conn->close(); +?> +``` + +### MySQLi Procedural + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = mysqli_connect($servername, $username, $password, $dbname); + +// Check connection +if (!$conn) { + die("Connection failed: " . mysqli_connect_error()); +} + +$sql = "INSERT INTO MyGuests (firstname, lastname, email) +VALUES ('John', 'Doe', 'john@example.com')"; + +if (mysqli_query($conn, $sql)) { + $last_id = mysqli_insert_id($conn); + echo "New record created successfully. Last inserted ID is: " . $last_id; +} else { + echo "Error: " . $sql . "<br>" . mysqli_error($conn); +} + +mysqli_close($conn); +?> +``` + +### PDO + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDBPDO"; + +try { + $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password); + // Set the PDO error mode to exception + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $sql = "INSERT INTO MyGuests (firstname, lastname, email) + VALUES ('John', 'Doe', 'john@example.com')"; + // Use exec() because no results are returned + $conn->exec($sql); + $last_id = $conn->lastInsertId(); + echo "New record created successfully. Last inserted ID is: " . $last_id; +} catch(PDOException $e) { + echo $sql . "<br>" . $e->getMessage(); +} + +$conn = null; +?> +``` + +**Key methods:** + +- MySQLi OO: `$conn->insert_id` +- MySQLi Procedural: `mysqli_insert_id($conn)` +- PDO: `$conn->lastInsertId()` + +--- + +## 7. Insert Multiple Records + +> **Source:** <https://www.w3schools.com/php/php_mysql_insert_multiple.asp> + +Multiple SQL statements can be executed with the `multi_query()` method (MySQLi) or by +grouping values (PDO). + +### MySQLi Object-Oriented (multi_query) + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = new mysqli($servername, $username, $password, $dbname); + +// Check connection +if ($conn->connect_error) { + die("Connection failed: " . $conn->connect_error); +} + +$sql = "INSERT INTO MyGuests (firstname, lastname, email) +VALUES ('John', 'Doe', 'john@example.com');"; +$sql .= "INSERT INTO MyGuests (firstname, lastname, email) +VALUES ('Mary', 'Moe', 'mary@example.com');"; +$sql .= "INSERT INTO MyGuests (firstname, lastname, email) +VALUES ('Julie', 'Dooley', 'julie@example.com')"; + +if ($conn->multi_query($sql) === TRUE) { + echo "New records created successfully"; +} else { + echo "Error: " . $sql . "<br>" . $conn->error; +} + +$conn->close(); +?> +``` + +### MySQLi Procedural (multi_query) + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = mysqli_connect($servername, $username, $password, $dbname); + +// Check connection +if (!$conn) { + die("Connection failed: " . mysqli_connect_error()); +} + +$sql = "INSERT INTO MyGuests (firstname, lastname, email) +VALUES ('John', 'Doe', 'john@example.com');"; +$sql .= "INSERT INTO MyGuests (firstname, lastname, email) +VALUES ('Mary', 'Moe', 'mary@example.com');"; +$sql .= "INSERT INTO MyGuests (firstname, lastname, email) +VALUES ('Julie', 'Dooley', 'julie@example.com')"; + +if (mysqli_multi_query($conn, $sql)) { + echo "New records created successfully"; +} else { + echo "Error: " . $sql . "<br>" . mysqli_error($conn); +} + +mysqli_close($conn); +?> +``` + +### PDO (Using Prepared Statements for Multiple Inserts) + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDBPDO"; + +try { + $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password); + // Set the PDO error mode to exception + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + // Begin a transaction + $conn->beginTransaction(); + + // Prepare the statement + $stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) + VALUES (:firstname, :lastname, :email)"); + + // Insert row 1 + $stmt->execute([ + ':firstname' => 'John', + ':lastname' => 'Doe', + ':email' => 'john@example.com' + ]); + + // Insert row 2 + $stmt->execute([ + ':firstname' => 'Mary', + ':lastname' => 'Moe', + ':email' => 'mary@example.com' + ]); + + // Insert row 3 + $stmt->execute([ + ':firstname' => 'Julie', + ':lastname' => 'Dooley', + ':email' => 'julie@example.com' + ]); + + // Commit the transaction + $conn->commit(); + echo "New records created successfully"; +} catch(PDOException $e) { + // Roll back the transaction if something failed + $conn->rollBack(); + echo "Error: " . $e->getMessage(); +} + +$conn = null; +?> +``` + +**Note:** Each SQL statement in the `multi_query()` string must be separated by a **semicolon**. +The PDO version uses prepared statements and transactions for safer, more reliable batch inserts. + +--- + +## 8. Prepared Statements + +> **Source:** <https://www.w3schools.com/php/php_mysql_prepared_statements.asp> + +Prepared statements are very useful against **SQL injection**. They are the recommended way to +execute queries with user-supplied data. + +### What Are Prepared Statements? + +A prepared statement is a feature used to execute the same (or similar) SQL statements +repeatedly with high efficiency. They work in two stages: + +1. **Prepare:** A SQL statement template is created and sent to the database. Certain values + are left unspecified, called **parameters** (labeled `?` or `:name`). Example: + `INSERT INTO MyGuests VALUES(?, ?, ?)` +2. **Execute:** The database parses, compiles, and optimizes the SQL statement template, and + stores the result without executing it. The application binds specific values to the + parameters and executes the statement. The statement can be executed as many times as needed + with different values. + +### Benefits of Prepared Statements + +- **Reduced parsing time:** The query is prepared only once even if it is executed multiple times. +- **Reduced bandwidth:** Only the parameters need to be sent each time, not the whole query. +- **Protection against SQL injection:** Parameter values are transmitted later using a different + protocol and do not need to be escaped. If the original statement template is not derived from + external input, SQL injection cannot occur. + +### MySQLi Prepared Statement (with Bound Parameters) + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = new mysqli($servername, $username, $password, $dbname); + +// Check connection +if ($conn->connect_error) { + die("Connection failed: " . $conn->connect_error); +} + +// Prepare and bind +$stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)"); +$stmt->bind_param("sss", $firstname, $lastname, $email); + +// Set parameters and execute +$firstname = "John"; +$lastname = "Doe"; +$email = "john@example.com"; +$stmt->execute(); + +$firstname = "Mary"; +$lastname = "Moe"; +$email = "mary@example.com"; +$stmt->execute(); + +$firstname = "Julie"; +$lastname = "Dooley"; +$email = "julie@example.com"; +$stmt->execute(); + +echo "New records created successfully"; + +$stmt->close(); +$conn->close(); +?> +``` + +**The `bind_param()` type string argument:** + +| Character | Description | +|-----------|-------------| +| `i` | integer | +| `d` | double | +| `s` | string | +| `b` | BLOB (binary large object) | + +Each parameter must have a type specified. By telling MySQL what type of data to expect, you +minimize the risk of SQL injection. + +### PDO Prepared Statement (with Named Parameters) + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDBPDO"; + +try { + $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password); + // Set the PDO error mode to exception + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + // Prepare SQL and bind parameters + $stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) + VALUES (:firstname, :lastname, :email)"); + $stmt->bindParam(':firstname', $firstname); + $stmt->bindParam(':lastname', $lastname); + $stmt->bindParam(':email', $email); + + // Insert row 1 + $firstname = "John"; + $lastname = "Doe"; + $email = "john@example.com"; + $stmt->execute(); + + // Insert row 2 + $firstname = "Mary"; + $lastname = "Moe"; + $email = "mary@example.com"; + $stmt->execute(); + + // Insert row 3 + $firstname = "Julie"; + $lastname = "Dooley"; + $email = "julie@example.com"; + $stmt->execute(); + + echo "New records created successfully"; +} catch(PDOException $e) { + echo "Error: " . $e->getMessage(); +} + +$conn = null; +?> +``` + +**Note:** In PDO, named parameters (`:firstname`) are used rather than `?` positional +placeholders (though PDO supports both). Named parameters are more readable. + +--- + +## 9. Select Data + +> **Source:** <https://www.w3schools.com/php/php_mysql_select.asp> + +The `SELECT` statement is used to select data from one or more tables. + +### SQL Syntax + +```sql +SELECT column_name(s) FROM table_name + +-- Or select all columns: +SELECT * FROM table_name +``` + +### MySQLi Object-Oriented + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = new mysqli($servername, $username, $password, $dbname); + +// Check connection +if ($conn->connect_error) { + die("Connection failed: " . $conn->connect_error); +} + +$sql = "SELECT id, firstname, lastname FROM MyGuests"; +$result = $conn->query($sql); + +if ($result->num_rows > 0) { + // Output data of each row + while($row = $result->fetch_assoc()) { + echo "id: " . $row["id"] . " - Name: " . $row["firstname"] . " " . $row["lastname"] . "<br>"; + } +} else { + echo "0 results"; +} + +$conn->close(); +?> +``` + +### MySQLi Procedural + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = mysqli_connect($servername, $username, $password, $dbname); + +// Check connection +if (!$conn) { + die("Connection failed: " . mysqli_connect_error()); +} + +$sql = "SELECT id, firstname, lastname FROM MyGuests"; +$result = mysqli_query($conn, $sql); + +if (mysqli_num_rows($result) > 0) { + // Output data of each row + while($row = mysqli_fetch_assoc($result)) { + echo "id: " . $row["id"] . " - Name: " . $row["firstname"] . " " . $row["lastname"] . "<br>"; + } +} else { + echo "0 results"; +} + +mysqli_close($conn); +?> +``` + +### PDO (with Prepared Statement) + +```php +<?php +echo "<table style='border: solid 1px black;'>"; +echo "<tr><th>Id</th><th>Firstname</th><th>Lastname</th></tr>"; + +class TableRows extends RecursiveIteratorIterator { + function __construct($it) { + parent::__construct($it, self::LEAVES_ONLY); + } + + function current() { + return "<td style='width:150px;border:1px solid black;'>" . parent::current() . "</td>"; + } + + function beginChildren() { + echo "<tr>"; + } + + function endChildren() { + echo "</tr>" . "\n"; + } +} + +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDBPDO"; + +try { + $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password); + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $stmt = $conn->prepare("SELECT id, firstname, lastname FROM MyGuests"); + $stmt->execute(); + + // Set the resulting array to associative + $result = $stmt->setFetchMode(PDO::FETCH_ASSOC); + foreach(new TableRows(new RecursiveArrayIterator($stmt->fetchAll())) as $k => $v) { + echo $v; + } +} catch(PDOException $e) { + echo "Error: " . $e->getMessage(); +} + +$conn = null; +echo "</table>"; +?> +``` + +**Simpler PDO Select (common pattern):** + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDBPDO"; + +try { + $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password); + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $stmt = $conn->prepare("SELECT id, firstname, lastname FROM MyGuests"); + $stmt->execute(); + + // Fetch all results as an associative array + $results = $stmt->fetchAll(PDO::FETCH_ASSOC); + + foreach ($results as $row) { + echo "id: " . $row["id"] . " - Name: " . $row["firstname"] . " " . $row["lastname"] . "<br>"; + } +} catch(PDOException $e) { + echo "Error: " . $e->getMessage(); +} + +$conn = null; +?> +``` + +**Key methods:** + +- `$result->num_rows` -- returns the number of rows in the result set (MySQLi OO). +- `$result->fetch_assoc()` -- fetches a result row as an associative array (MySQLi OO). +- `$stmt->fetchAll(PDO::FETCH_ASSOC)` -- returns an array of all rows (PDO). + +--- + +## 10. Select with WHERE + +> **Source:** <https://www.w3schools.com/php/php_mysql_select_where.asp> + +The `WHERE` clause is used to filter records and extract only those that fulfill specified +conditions. + +### SQL Syntax + +```sql +SELECT column_name(s) FROM table_name WHERE column_name operator value +``` + +### MySQLi Object-Oriented + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = new mysqli($servername, $username, $password, $dbname); + +// Check connection +if ($conn->connect_error) { + die("Connection failed: " . $conn->connect_error); +} + +$sql = "SELECT id, firstname, lastname FROM MyGuests WHERE lastname='Doe'"; +$result = $conn->query($sql); + +if ($result->num_rows > 0) { + // Output data of each row + while($row = $result->fetch_assoc()) { + echo "id: " . $row["id"] . " - Name: " . $row["firstname"] . " " . $row["lastname"] . "<br>"; + } +} else { + echo "0 results"; +} + +$conn->close(); +?> +``` + +### MySQLi Procedural + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = mysqli_connect($servername, $username, $password, $dbname); + +// Check connection +if (!$conn) { + die("Connection failed: " . mysqli_connect_error()); +} + +$sql = "SELECT id, firstname, lastname FROM MyGuests WHERE lastname='Doe'"; +$result = mysqli_query($conn, $sql); + +if (mysqli_num_rows($result) > 0) { + while($row = mysqli_fetch_assoc($result)) { + echo "id: " . $row["id"] . " - Name: " . $row["firstname"] . " " . $row["lastname"] . "<br>"; + } +} else { + echo "0 results"; +} + +mysqli_close($conn); +?> +``` + +### PDO (with Prepared Statement -- Recommended) + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDBPDO"; + +try { + $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password); + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $stmt = $conn->prepare("SELECT id, firstname, lastname FROM MyGuests WHERE lastname = :lastname"); + $stmt->bindParam(':lastname', $lastname); + + $lastname = "Doe"; + $stmt->execute(); + + $results = $stmt->fetchAll(PDO::FETCH_ASSOC); + foreach ($results as $row) { + echo "id: " . $row["id"] . " - Name: " . $row["firstname"] . " " . $row["lastname"] . "<br>"; + } +} catch(PDOException $e) { + echo "Error: " . $e->getMessage(); +} + +$conn = null; +?> +``` + +**Common WHERE operators:** + +| Operator | Description | +|----------|-------------| +| `=` | Equal | +| `<>` or `!=` | Not equal | +| `>` | Greater than | +| `<` | Less than | +| `>=` | Greater than or equal | +| `<=` | Less than or equal | +| `BETWEEN` | Between an inclusive range | +| `LIKE` | Search for a pattern | +| `IN` | To specify multiple possible values for a column | + +**Important:** Always use prepared statements with bound parameters when using user-supplied +values in WHERE clauses to prevent SQL injection. + +--- + +## 11. Select with ORDER BY + +> **Source:** <https://www.w3schools.com/php/php_mysql_select_orderby.asp> + +The `ORDER BY` clause is used to sort the result-set in ascending or descending order. By +default, it sorts in **ascending** order. Use the `DESC` keyword to sort in descending order. + +### SQL Syntax + +```sql +SELECT column_name(s) FROM table_name ORDER BY column_name ASC|DESC +``` + +### MySQLi Object-Oriented + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = new mysqli($servername, $username, $password, $dbname); + +// Check connection +if ($conn->connect_error) { + die("Connection failed: " . $conn->connect_error); +} + +$sql = "SELECT id, firstname, lastname FROM MyGuests ORDER BY lastname"; +$result = $conn->query($sql); + +if ($result->num_rows > 0) { + while($row = $result->fetch_assoc()) { + echo "id: " . $row["id"] . " - Name: " . $row["firstname"] . " " . $row["lastname"] . "<br>"; + } +} else { + echo "0 results"; +} + +$conn->close(); +?> +``` + +### Descending Order Example + +```php +$sql = "SELECT id, firstname, lastname FROM MyGuests ORDER BY lastname DESC"; +``` + +### Multiple Column Sorting + +You can order by more than one column. When ordering by multiple columns, the second column is +only used when the first column values are the same: + +```sql +SELECT * FROM MyGuests ORDER BY lastname ASC, firstname ASC +``` + +### MySQLi Procedural + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = mysqli_connect($servername, $username, $password, $dbname); + +// Check connection +if (!$conn) { + die("Connection failed: " . mysqli_connect_error()); +} + +$sql = "SELECT id, firstname, lastname FROM MyGuests ORDER BY lastname"; +$result = mysqli_query($conn, $sql); + +if (mysqli_num_rows($result) > 0) { + while($row = mysqli_fetch_assoc($result)) { + echo "id: " . $row["id"] . " - Name: " . $row["firstname"] . " " . $row["lastname"] . "<br>"; + } +} else { + echo "0 results"; +} + +mysqli_close($conn); +?> +``` + +### PDO + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDBPDO"; + +try { + $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password); + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $stmt = $conn->prepare("SELECT id, firstname, lastname FROM MyGuests ORDER BY lastname"); + $stmt->execute(); + + $results = $stmt->fetchAll(PDO::FETCH_ASSOC); + foreach ($results as $row) { + echo "id: " . $row["id"] . " - Name: " . $row["firstname"] . " " . $row["lastname"] . "<br>"; + } +} catch(PDOException $e) { + echo "Error: " . $e->getMessage(); +} + +$conn = null; +?> +``` + +--- + +## 12. Delete Data + +> **Source:** <https://www.w3schools.com/php/php_mysql_delete.asp> + +The `DELETE` statement is used to delete records from a table. + +### SQL Syntax + +```sql +DELETE FROM table_name WHERE some_column = some_value +``` + +**Important:** The `WHERE` clause specifies which records should be deleted. If you omit the +WHERE clause, **ALL records will be deleted!** + +### MySQLi Object-Oriented + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = new mysqli($servername, $username, $password, $dbname); + +// Check connection +if ($conn->connect_error) { + die("Connection failed: " . $conn->connect_error); +} + +// SQL to delete a record +$sql = "DELETE FROM MyGuests WHERE id=3"; + +if ($conn->query($sql) === TRUE) { + echo "Record deleted successfully"; +} else { + echo "Error deleting record: " . $conn->error; +} + +$conn->close(); +?> +``` + +### MySQLi Procedural + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = mysqli_connect($servername, $username, $password, $dbname); + +// Check connection +if (!$conn) { + die("Connection failed: " . mysqli_connect_error()); +} + +// SQL to delete a record +$sql = "DELETE FROM MyGuests WHERE id=3"; + +if (mysqli_query($conn, $sql)) { + echo "Record deleted successfully"; +} else { + echo "Error deleting record: " . mysqli_error($conn); +} + +mysqli_close($conn); +?> +``` + +### PDO (with Prepared Statement) + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDBPDO"; + +try { + $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password); + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + // Prepare the delete statement + $stmt = $conn->prepare("DELETE FROM MyGuests WHERE id = :id"); + $stmt->bindParam(':id', $id); + + $id = 3; + $stmt->execute(); + + echo "Record deleted successfully"; +} catch(PDOException $e) { + echo "Error: " . $e->getMessage(); +} + +$conn = null; +?> +``` + +**Warning:** Be very careful when deleting records. You cannot undo this statement! + +--- + +## 13. Update Data + +> **Source:** <https://www.w3schools.com/php/php_mysql_update.asp> + +The `UPDATE` statement is used to update existing records in a table. + +### SQL Syntax + +```sql +UPDATE table_name SET column1=value1, column2=value2, ... WHERE some_column=some_value +``` + +**Important:** The `WHERE` clause specifies which record(s) should be updated. If you omit the +WHERE clause, **ALL records will be updated!** + +### MySQLi Object-Oriented + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = new mysqli($servername, $username, $password, $dbname); + +// Check connection +if ($conn->connect_error) { + die("Connection failed: " . $conn->connect_error); +} + +$sql = "UPDATE MyGuests SET lastname='Doe' WHERE id=2"; + +if ($conn->query($sql) === TRUE) { + echo "Record updated successfully"; +} else { + echo "Error updating record: " . $conn->error; +} + +$conn->close(); +?> +``` + +### MySQLi Procedural + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = mysqli_connect($servername, $username, $password, $dbname); + +// Check connection +if (!$conn) { + die("Connection failed: " . mysqli_connect_error()); +} + +$sql = "UPDATE MyGuests SET lastname='Doe' WHERE id=2"; + +if (mysqli_query($conn, $sql)) { + echo "Record updated successfully"; +} else { + echo "Error updating record: " . mysqli_error($conn); +} + +mysqli_close($conn); +?> +``` + +### PDO (with Prepared Statement) + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDBPDO"; + +try { + $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password); + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $stmt = $conn->prepare("UPDATE MyGuests SET lastname = :lastname WHERE id = :id"); + $stmt->bindParam(':lastname', $lastname); + $stmt->bindParam(':id', $id); + + $lastname = "Doe"; + $id = 2; + $stmt->execute(); + + echo "Record updated successfully"; +} catch(PDOException $e) { + echo "Error: " . $e->getMessage(); +} + +$conn = null; +?> +``` + +**Note:** The `$conn->query($sql)` returns `TRUE` on success. To check how many rows were +affected, use `$conn->affected_rows` (MySQLi) or `$stmt->rowCount()` (PDO). + +--- + +## 14. Select with LIMIT + +> **Source:** <https://www.w3schools.com/php/php_mysql_select_limit.asp> + +The `LIMIT` clause is used to specify the number of records to return. This is useful for +paginating results or displaying a fixed number of records per page. + +### SQL Syntax + +```sql +SELECT column_name(s) FROM table_name LIMIT number + +-- With offset (for pagination): +SELECT column_name(s) FROM table_name LIMIT offset, count +``` + +**Note:** The first row starts at offset `0` (not `1`). + +### MySQLi Object-Oriented + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = new mysqli($servername, $username, $password, $dbname); + +// Check connection +if ($conn->connect_error) { + die("Connection failed: " . $conn->connect_error); +} + +$sql = "SELECT * FROM Orders LIMIT 30"; +$result = $conn->query($sql); + +if ($result->num_rows > 0) { + while($row = $result->fetch_assoc()) { + echo "id: " . $row["id"] . "<br>"; + } +} else { + echo "0 results"; +} + +$conn->close(); +?> +``` + +### Using LIMIT with an Offset (Pagination) + +The `LIMIT` clause can take two values: `LIMIT offset, count`. + +- The **offset** specifies where to start returning records (first record is 0). +- The **count** specifies the maximum number of records to return. + +```sql +-- Return records 16-30 (start from offset 15, return 15 records): +SELECT * FROM Orders LIMIT 15, 15 +``` + +### Pagination Example + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDB"; + +// Create connection +$conn = new mysqli($servername, $username, $password, $dbname); + +// Check connection +if ($conn->connect_error) { + die("Connection failed: " . $conn->connect_error); +} + +// Number of results per page +$results_per_page = 10; + +// Current page (from URL parameter) +$page = isset($_GET['page']) ? (int)$_GET['page'] : 1; + +// Calculate the offset +$offset = ($page - 1) * $results_per_page; + +// Select records with LIMIT and OFFSET +$sql = "SELECT * FROM Orders LIMIT $offset, $results_per_page"; +$result = $conn->query($sql); + +if ($result->num_rows > 0) { + while($row = $result->fetch_assoc()) { + echo "id: " . $row["id"] . "<br>"; + } +} else { + echo "0 results"; +} + +$conn->close(); +?> +``` + +### PDO with LIMIT (Prepared Statement) + +```php +<?php +$servername = "localhost"; +$username = "username"; +$password = "password"; +$dbname = "myDBPDO"; + +try { + $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password); + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $limit = 10; + $offset = 0; + + $stmt = $conn->prepare("SELECT * FROM Orders LIMIT :offset, :limit"); + $stmt->bindParam(':offset', $offset, PDO::PARAM_INT); + $stmt->bindParam(':limit', $limit, PDO::PARAM_INT); + $stmt->execute(); + + $results = $stmt->fetchAll(PDO::FETCH_ASSOC); + foreach ($results as $row) { + echo "id: " . $row["id"] . "<br>"; + } +} catch(PDOException $e) { + echo "Error: " . $e->getMessage(); +} + +$conn = null; +?> +``` + +**Important:** When using LIMIT with prepared statements in PDO, you must explicitly bind +the values as integers using `PDO::PARAM_INT`, otherwise PDO treats them as strings and wraps +them in quotes, which causes a SQL error. + +--- + +## Quick Reference Summary + +### Connection Patterns + +| Method | Connect | Close | +|--------|---------|-------| +| MySQLi OO | `new mysqli($host, $user, $pass, $db)` | `$conn->close()` | +| MySQLi Proc | `mysqli_connect($host, $user, $pass, $db)` | `mysqli_close($conn)` | +| PDO | `new PDO("mysql:host=$host;dbname=$db", $user, $pass)` | `$conn = null` | + +### CRUD Operations + +| Operation | SQL Command | +|-----------|-------------| +| **C**reate | `INSERT INTO table (col1, col2) VALUES (val1, val2)` | +| **R**ead | `SELECT col1, col2 FROM table WHERE condition` | +| **U**pdate | `UPDATE table SET col1=val1 WHERE condition` | +| **D**elete | `DELETE FROM table WHERE condition` | + +### Query Modifiers + +| Modifier | Purpose | Example | +|----------|---------|---------| +| `WHERE` | Filter rows | `WHERE id = 1` | +| `ORDER BY` | Sort results | `ORDER BY name ASC` | +| `LIMIT` | Restrict row count | `LIMIT 10` | +| `LIMIT offset, count` | Pagination | `LIMIT 20, 10` | + +### MySQLi bind_param Types + +| Type | Character | +|------|-----------| +| Integer | `i` | +| Double | `d` | +| String | `s` | +| BLOB | `b` | + +### Security Best Practices + +1. **Always** use prepared statements with bound parameters for user-supplied data. +2. **Never** insert user input directly into SQL query strings. +3. Use `PDO::ERRMODE_EXCEPTION` to handle errors properly. +4. Validate and sanitize all user input before processing. +5. Use the principle of least privilege for database user accounts. +6. Store database credentials outside the web root and use environment variables when possible. + +--- + +*This reference was consolidated from W3Schools PHP MySQL tutorial pages.* +*Source URLs are listed at the beginning of each section.* diff --git a/skills/create-web-form/references/progressive-web-app.md b/skills/create-web-form/references/progressive-web-app.md new file mode 100644 index 00000000..defb3baf --- /dev/null +++ b/skills/create-web-form/references/progressive-web-app.md @@ -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` diff --git a/skills/create-web-form/references/python-as-web-framework.md b/skills/create-web-form/references/python-as-web-framework.md new file mode 100644 index 00000000..26832168 --- /dev/null +++ b/skills/create-web-form/references/python-as-web-framework.md @@ -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 + + + {% if name %} +

Hello, {{ name }}!

+ {% else %} +

Hello, World!

+ {% endif %} + + +``` + +### 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 + + + + {% block title %}Default Title{% endblock %} + + +
+ {% block header %} +

My Website

+ {% endblock %} +
+ +
+ {% block content %}{% endblock %} +
+ +
+ {% block footer %} +

Footer content

+ {% endblock %} +
+ + +``` + +**Child template (`home.html`):** + +```html +{% extends "base.html" %} + +{% block title %}Home Page{% endblock %} + +{% block content %} +

Welcome!

+

This is the home page.

+{% endblock %} +``` + +### Loops and Conditionals + +```html + + + + +{% if users %} +
    + {% for user in users %} +
  • {{ user.username }}
  • + {% endfor %} +
+{% else %} +

No users found.

+{% 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 +
+ + + + + + + + + + +
+``` + +### 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 + + +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/') +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. diff --git a/skills/create-web-form/references/python-contact-form.md b/skills/create-web-form/references/python-contact-form.md new file mode 100644 index 00000000..42a064fa --- /dev/null +++ b/skills/create-web-form/references/python-contact-form.md @@ -0,0 +1,453 @@ +# Python Contact Form Reference + +> Source: + +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 + + + + + + Contact Us + + +

Contact Us

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +``` + +### 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.hidden_tag() }} + +
+``` + +--- + +## 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. diff --git a/skills/create-web-form/references/python-flask-app.md b/skills/create-web-form/references/python-flask-app.md new file mode 100644 index 00000000..80540d89 --- /dev/null +++ b/skills/create-web-form/references/python-flask-app.md @@ -0,0 +1,449 @@ +# Python Flask App Reference + +> Source: + +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/') +def show_user(username): + return f'User: {username}' + +@app.route('/post/') +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/') +def hello(name): + return render_template('hello.html', name=name) +``` + +### Template Inheritance + +**Base template (`templates/base.html`):** + +```html + + + + + {% block title %}My App{% endblock %} + + + + + +
+ {% block content %}{% endblock %} +
+ +
+

My Web App

+
+ + +``` + +**Child template (`templates/home.html`):** + +```html +{% extends "base.html" %} + +{% block title %}Home{% endblock %} + +{% block content %} +

Welcome to My App

+

This is the home page.

+{% 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 %} +

Hello, {{ user.name }}!

+{% else %} +

Hello, stranger!

+{% endif %} + +
    +{% for item in items %} +
  • {{ item }}
  • +{% endfor %} +
+``` + +--- + +## 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 + + +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'' +``` + +### 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. diff --git a/skills/create-web-form/references/python-flask.md b/skills/create-web-form/references/python-flask.md new file mode 100644 index 00000000..6010de62 --- /dev/null +++ b/skills/create-web-form/references/python-flask.md @@ -0,0 +1,432 @@ +# Python Flask Forms Reference + +> Source: + +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.hidden_tag() }} + +
+ {{ form.username.label }} + {{ form.username(class="form-control", placeholder="Enter username") }} + {% for error in form.username.errors %} + {{ error }} + {% endfor %} +
+ +
+ {{ form.email.label }} + {{ form.email(class="form-control", placeholder="Enter email") }} + {% for error in form.email.errors %} + {{ error }} + {% endfor %} +
+ +
+ {{ form.password.label }} + {{ form.password(class="form-control") }} + {% for error in form.password.errors %} + {{ error }} + {% endfor %} +
+ +
+ {{ form.confirm_password.label }} + {{ form.confirm_password(class="form-control") }} + {% for error in form.confirm_password.errors %} + {{ error }} + {% endfor %} +
+ + {{ form.submit(class="btn btn-primary") }} +
+``` + +### Key Template Elements + +| Element | Purpose | +|---------|---------| +| `{{ form.hidden_tag() }}` | Renders the hidden CSRF token field | +| `{{ form.field.label }}` | Renders the `