Added issues that are going to be tracked and will be deeply considering changes based on DX.
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -0,0 +1,525 @@
|
||||
# Component API Smells
|
||||
|
||||
This document catalogs potential complaints about the current component/template API.
|
||||
|
||||
Each item includes:
|
||||
|
||||
- Problem
|
||||
- Why it hurts
|
||||
- Potential solutions
|
||||
- Consequences/costs
|
||||
|
||||
## 1) Magic Strings for Variants, Sizes, Types, Directions
|
||||
|
||||
Problem:
|
||||
- Many components use raw strings for semantic options (`variant`, `size`, `type`, `direction`, `align`, etc.).
|
||||
- Invalid values often silently fall back to defaults.
|
||||
|
||||
Why it hurts:
|
||||
- No compile-time safety.
|
||||
- Typos are easy to miss.
|
||||
- Weak IntelliSense discoverability.
|
||||
|
||||
Potential solutions:
|
||||
- Replace string options with enums for common semantic domains.
|
||||
- Generate constants classes per component for non-breaking intermediate step.
|
||||
- Add analyzers that validate allowed literals where strings are retained.
|
||||
|
||||
Consequences/costs:
|
||||
- Enums can be breaking if public signatures change.
|
||||
- Constants are low cost but do not fully prevent invalid values.
|
||||
- Analyzer route adds tooling complexity.
|
||||
|
||||
## 2) Inconsistent Styling Extensibility (`extraClasses` and wrappers)
|
||||
|
||||
Problem:
|
||||
- Some components have `extraClasses`; others do not.
|
||||
- Developers often wrap components in outer `div` just to apply layout/styling.
|
||||
|
||||
Why it hurts:
|
||||
- No consistent mental model.
|
||||
- Extra wrapper markup increases noise and nesting depth.
|
||||
|
||||
Potential solutions:
|
||||
- Add a standard `className` (or `extraClasses`) parameter to every component.
|
||||
- Support class merging utility behavior in a shared helper.
|
||||
|
||||
Consequences/costs:
|
||||
- Public constructor expansion across many components.
|
||||
- Need policy for precedence (base classes first vs custom classes first).
|
||||
|
||||
## 3) Missing Uniform Attribute Pass-Through
|
||||
|
||||
Problem:
|
||||
- Attribute extensibility is fragmented (`hxAttrs` in some places, none in others).
|
||||
- No first-class support for arbitrary `aria-*`, `data-*`, test IDs, analytics attributes.
|
||||
|
||||
Why it hurts:
|
||||
- Manual string composition is error-prone.
|
||||
- Difficult accessibility and testing instrumentation.
|
||||
|
||||
Potential solutions:
|
||||
- Add a shared attributes bag type (`IReadOnlyDictionary<string, string?>`).
|
||||
- Keep `hxAttrs` temporarily as compatibility shim.
|
||||
|
||||
Consequences/costs:
|
||||
- Larger refactor surface.
|
||||
- Slight allocation/processing overhead.
|
||||
- Requires HTML attribute encoding rules in one central place.
|
||||
|
||||
## 4) `hxAttrs` Raw String Footgun
|
||||
|
||||
Problem:
|
||||
- Raw attribute strings allow malformed markup or accidental injection.
|
||||
|
||||
Why it hurts:
|
||||
- Hard-to-debug render bugs.
|
||||
- Security posture depends on each caller doing manual encoding correctly.
|
||||
|
||||
Potential solutions:
|
||||
- Deprecate raw `hxAttrs` in favor of typed/structured attrs.
|
||||
- Provide safe helper methods to construct HTMX attribute sets.
|
||||
|
||||
Consequences/costs:
|
||||
- Migration needed for existing call sites.
|
||||
- Potentially breaking unless a gradual fallback is kept.
|
||||
|
||||
## 5) Unsafe-by-Default Raw HTML Content Paths
|
||||
|
||||
Problem:
|
||||
- Several components accept string content that is rendered as raw HTML.
|
||||
- Caller must remember to encode user-provided values.
|
||||
|
||||
Why it hurts:
|
||||
- XSS risk in real application code.
|
||||
- Easy to misuse when moving quickly.
|
||||
|
||||
Potential solutions:
|
||||
- Safe-by-default encoding for plain string inputs.
|
||||
- Separate APIs for encoded text vs trusted HTML (explicit escape hatch).
|
||||
- Introduce a `SafeHtml` wrapper type for intentional raw HTML.
|
||||
|
||||
Consequences/costs:
|
||||
- Safe-by-default may break current behavior for callers relying on raw HTML.
|
||||
- Trusted-HTML API adds conceptual complexity, but clearer intent.
|
||||
|
||||
## 6) Inconsistent Security Guidance in Component Docs
|
||||
|
||||
Problem:
|
||||
- Some docs mention encoding; others do not provide clear warnings.
|
||||
|
||||
Why it hurts:
|
||||
- Security correctness relies on tribal knowledge.
|
||||
|
||||
Potential solutions:
|
||||
- Add a standardized "Security" section to every component doc.
|
||||
- Include explicit examples: safe input, unsafe input, and fix.
|
||||
|
||||
Consequences/costs:
|
||||
- Documentation maintenance overhead.
|
||||
- Strong DX/security benefit for low implementation cost.
|
||||
|
||||
## 7) No Explicit "Component Props" Model in Markup
|
||||
|
||||
Problem:
|
||||
- Slots replace placeholders, but there is no direct concept of passing typed props in `.htmx` markup itself.
|
||||
- Dynamic behavior is mostly constructor-centric in `.htmx.cs`.
|
||||
|
||||
Why it hurts:
|
||||
- Feels unlike modern component systems where props are explicit and local.
|
||||
- New users may expect inline component parameterization and be surprised.
|
||||
|
||||
Potential solutions:
|
||||
- Document this limitation clearly as a design constraint.
|
||||
- Add a generated props record convention per component/page.
|
||||
- Explore optional parameterized slot syntax in generator (long-term).
|
||||
|
||||
Consequences/costs:
|
||||
- Props model requires generator design changes.
|
||||
- Parameterized slot syntax is high complexity and may conflict with AOT simplicity.
|
||||
|
||||
## 8) Constructor Bloat and Low Readability
|
||||
|
||||
Problem:
|
||||
- Some components expose many optional parameters, often multiple strings.
|
||||
|
||||
Why it hurts:
|
||||
- Ambiguous calls and poor self-documentation.
|
||||
- Easy to mis-order arguments.
|
||||
|
||||
Potential solutions:
|
||||
- Favor required args + options record pattern.
|
||||
- Add fluent builders for complex components.
|
||||
|
||||
Consequences/costs:
|
||||
- Options records improve readability but introduce extra types.
|
||||
- Builders can increase allocations and complexity.
|
||||
|
||||
## 9) Tuple-Based APIs for Complex Components
|
||||
|
||||
Problem:
|
||||
- Components like tabs/accordion/dropdown/table rely on tuple collections.
|
||||
|
||||
Why it hurts:
|
||||
- Tuples are easy to misuse and harder to read than named objects.
|
||||
- Harder to evolve APIs without breaking all call sites.
|
||||
|
||||
Potential solutions:
|
||||
- Replace tuple parameters with named records (`TabItem`, `AccordionItem`, etc.).
|
||||
|
||||
Consequences/costs:
|
||||
- Migration churn across existing usage.
|
||||
- Clear long-term maintainability win.
|
||||
|
||||
## 10) Missing Validation Feedback for Invalid Inputs
|
||||
|
||||
Problem:
|
||||
- Invalid option values often degrade silently rather than failing fast.
|
||||
|
||||
Why it hurts:
|
||||
- Bugs are hidden and discovered late.
|
||||
|
||||
Potential solutions:
|
||||
- Add debug-time validation with clear exceptions/messages.
|
||||
- Optionally emit logs/diagnostics in production with safe defaults.
|
||||
|
||||
Consequences/costs:
|
||||
- Strict runtime validation can be breaking for existing invalid usages.
|
||||
- Diagnostics-only mode is safer for migration.
|
||||
|
||||
## 11) Inconsistent Boolean Option Naming
|
||||
|
||||
Problem:
|
||||
- Different components use varying naming styles for booleans and toggles.
|
||||
|
||||
Why it hurts:
|
||||
- Low API predictability.
|
||||
|
||||
Potential solutions:
|
||||
- Define naming conventions (`isX`, `hasX`, `enableX`) and enforce globally.
|
||||
|
||||
Consequences/costs:
|
||||
- Rename churn if normalized retroactively.
|
||||
|
||||
## 12) CSS Contract Coupled to JS via Hidden Class Names
|
||||
|
||||
Problem:
|
||||
- Interactive behavior relies on specific class/data selectors that are effectively API contracts.
|
||||
|
||||
Why it hurts:
|
||||
- Refactoring classes can break behavior.
|
||||
- Coupling is not obvious from constructor APIs.
|
||||
|
||||
Potential solutions:
|
||||
- Document required selectors/events in each interactive component doc.
|
||||
- Prefer stable `data-component`/`data-role` markers over purely visual class names.
|
||||
|
||||
Consequences/costs:
|
||||
- Markup updates across components and JS.
|
||||
- Better long-term resilience to style refactors.
|
||||
|
||||
## 13) Runtime Behavior Dependencies Not Surfaced in API
|
||||
|
||||
Problem:
|
||||
- Components requiring JS initialization do not expose that requirement in code signatures.
|
||||
|
||||
Why it hurts:
|
||||
- Silent "renders but does not work" failures.
|
||||
|
||||
Potential solutions:
|
||||
- Add `Requires JavaScript` section in docs and XML comments.
|
||||
- Add lightweight marker interface or metadata attribute for interactive components.
|
||||
|
||||
Consequences/costs:
|
||||
- Minimal runtime cost; mostly documentation/tooling work.
|
||||
|
||||
## 14) Accessibility Ergonomics Gaps
|
||||
|
||||
Problem:
|
||||
- No consistent way to pass `aria-*`, `id`, `for`, `describedby` across all components.
|
||||
|
||||
Why it hurts:
|
||||
- Accessibility quality depends on manual wrapper hacks.
|
||||
|
||||
Potential solutions:
|
||||
- Introduce shared accessible options type.
|
||||
- Provide defaults and enforce required labels where relevant.
|
||||
|
||||
Consequences/costs:
|
||||
- Constructor changes and additional validation logic.
|
||||
|
||||
## 15) Testability Friction (No Standard Test IDs)
|
||||
|
||||
Problem:
|
||||
- No consistent `data-testid` or attribute pass-through strategy.
|
||||
|
||||
Why it hurts:
|
||||
- E2E selectors become brittle (class/text-based selectors).
|
||||
|
||||
Potential solutions:
|
||||
- Add standard attributes bag and testing guidance.
|
||||
- Add `testId` convenience parameter in interactive/form primitives.
|
||||
|
||||
Consequences/costs:
|
||||
- Minor API surface increase.
|
||||
- Significant test stability benefit.
|
||||
|
||||
## 16) Documentation Discoverability Gaps
|
||||
|
||||
Problem:
|
||||
- Component docs focus on usage but under-emphasize known limitations and smell areas.
|
||||
|
||||
Why it hurts:
|
||||
- New contributors re-learn the same constraints repeatedly.
|
||||
|
||||
Potential solutions:
|
||||
- Add dedicated docs for limitations, anti-patterns, and migration strategy.
|
||||
- Add an index from component reference into Issues docs.
|
||||
|
||||
Consequences/costs:
|
||||
- Ongoing documentation upkeep.
|
||||
|
||||
## 17) Inconsistent Naming (`extraClasses` vs alternatives)
|
||||
|
||||
Problem:
|
||||
- Similar concepts have inconsistent parameter names.
|
||||
|
||||
Why it hurts:
|
||||
- Context switching overhead.
|
||||
|
||||
Potential solutions:
|
||||
- Standardize naming dictionary and enforce in reviews.
|
||||
- Offer temporary backward-compatible aliases.
|
||||
|
||||
Consequences/costs:
|
||||
- Alias support increases short-term complexity.
|
||||
|
||||
## 18) Lack of Strongly-Typed Domain Primitives
|
||||
|
||||
Problem:
|
||||
- IDs, route paths, CSS classes, and labels are all plain strings.
|
||||
|
||||
Why it hurts:
|
||||
- Accidental parameter swaps and weak intent signaling.
|
||||
|
||||
Potential solutions:
|
||||
- Introduce lightweight value objects or records for high-value domains (`DialogId`, `CssClassList`, etc.).
|
||||
|
||||
Consequences/costs:
|
||||
- Added type count and conversion code.
|
||||
- Better readability and safer APIs.
|
||||
|
||||
## 19) Missing Centralized Class Composition Policy
|
||||
|
||||
Problem:
|
||||
- Tailwind class strings are composed ad-hoc in constructors.
|
||||
|
||||
Why it hurts:
|
||||
- Risk of duplicate/conflicting classes.
|
||||
- Hard to audit variant behavior consistency.
|
||||
|
||||
Potential solutions:
|
||||
- Add shared class composition helper utilities.
|
||||
- Optionally adopt a deterministic merge utility pattern.
|
||||
|
||||
Consequences/costs:
|
||||
- New utility dependency or internal helper maintenance.
|
||||
|
||||
## 20) Limited Error Reporting for Misconfigured Interactive Components
|
||||
|
||||
Problem:
|
||||
- Missing/incorrect JS hooks often fail quietly.
|
||||
|
||||
Why it hurts:
|
||||
- Time-consuming debugging.
|
||||
|
||||
Potential solutions:
|
||||
- Development-only console warnings/assertions from `components.js` when expected markers are missing.
|
||||
|
||||
Consequences/costs:
|
||||
- Slight JS complexity increase.
|
||||
- Better troubleshooting experience.
|
||||
|
||||
## 21) Form Component API Inconsistency
|
||||
|
||||
Problem:
|
||||
- Form primitives vary in how they accept value/default/checked/attrs/labels.
|
||||
|
||||
Why it hurts:
|
||||
- Hard to predict usage patterns across components.
|
||||
|
||||
Potential solutions:
|
||||
- Define a shared form control contract:
|
||||
- `name`, `id`, `label`, `value`, `disabled`, `required`, `className`, `attributes`
|
||||
|
||||
Consequences/costs:
|
||||
- Widespread API harmonization work.
|
||||
- Major usability win once stabilized.
|
||||
|
||||
## 22) No First-Class Validation/Error State Patterns
|
||||
|
||||
Problem:
|
||||
- Error display, invalid styling, and message linkage are largely ad-hoc.
|
||||
|
||||
Why it hurts:
|
||||
- Inconsistent UX and accessibility for validation states.
|
||||
|
||||
Potential solutions:
|
||||
- Add canonical form-field wrapper component and error semantics.
|
||||
- Add helper patterns in docs for mapping server validation to components.
|
||||
|
||||
Consequences/costs:
|
||||
- Additional abstractions and migration.
|
||||
|
||||
## 23) Table API Lacks Strong Cell/Column Models
|
||||
|
||||
Problem:
|
||||
- Table inputs as nested strings are simplistic and rigid.
|
||||
|
||||
Why it hurts:
|
||||
- Hard to represent links, badges, actions, and per-cell semantics safely.
|
||||
|
||||
Potential solutions:
|
||||
- Introduce column and row models with typed cell renderers.
|
||||
- Support text cell vs trusted HTML cell explicit APIs.
|
||||
|
||||
Consequences/costs:
|
||||
- Significant redesign effort for table API.
|
||||
- High payoff for real-world usage.
|
||||
|
||||
## 24) Potential Over-Eager Precomputation in Constructors
|
||||
|
||||
Problem:
|
||||
- Some components precompute heavy HTML payloads in constructor.
|
||||
|
||||
Why it hurts:
|
||||
- Allocation spikes for large datasets.
|
||||
- Can surprise developers expecting render-time streaming.
|
||||
|
||||
Potential solutions:
|
||||
- Lazy compute/cache expensive sections.
|
||||
- Document performance profile and guardrails per component.
|
||||
|
||||
Consequences/costs:
|
||||
- Possible complexity in caching invalidation.
|
||||
- Better performance transparency.
|
||||
|
||||
## 25) No Compatibility Policy for API Evolution
|
||||
|
||||
Problem:
|
||||
- No explicit deprecation policy for parameter renames or behavior changes.
|
||||
|
||||
Why it hurts:
|
||||
- Contributors hesitate to improve APIs due to break risk.
|
||||
|
||||
Potential solutions:
|
||||
- Define semver/deprecation policy in docs.
|
||||
- Use staged migration with obsolete annotations.
|
||||
|
||||
Consequences/costs:
|
||||
- Process overhead, but critical for long-term maintainability.
|
||||
|
||||
## 26) No Unified Component Design Principles Doc
|
||||
|
||||
Problem:
|
||||
- Patterns are documented, but not as enforceable design principles.
|
||||
|
||||
Why it hurts:
|
||||
- New components may diverge in API style.
|
||||
|
||||
Potential solutions:
|
||||
- Publish a component API style guide with mandatory rules and preferred patterns.
|
||||
|
||||
Consequences/costs:
|
||||
- Requires reviewer discipline.
|
||||
|
||||
## 27) Internationalization (i18n) Boundaries Not Explicit
|
||||
|
||||
Problem:
|
||||
- Many labels/content are plain strings without explicit localization guidance.
|
||||
|
||||
Why it hurts:
|
||||
- Inconsistent localization strategy across pages/components.
|
||||
|
||||
Potential solutions:
|
||||
- Add docs for localizable boundaries and resource integration patterns.
|
||||
|
||||
Consequences/costs:
|
||||
- Documentation and integration work.
|
||||
|
||||
## 28) Missing "Known Limitations" Section in Component Reference Entry Point
|
||||
|
||||
Problem:
|
||||
- The main component reference does not prominently call out systemic limitations.
|
||||
|
||||
Why it hurts:
|
||||
- Developers discover constraints by trial and error.
|
||||
|
||||
Potential solutions:
|
||||
- Add up-front limitations and issue tracker links in component reference.
|
||||
|
||||
Consequences/costs:
|
||||
- Low cost; immediate discoverability gains.
|
||||
|
||||
## 29) API Surface Differs Across Similar Components
|
||||
|
||||
Problem:
|
||||
- Similar categories (display/form/interactive) do not expose comparable extension points.
|
||||
|
||||
Why it hurts:
|
||||
- Surprising differences force re-learning per component.
|
||||
|
||||
Potential solutions:
|
||||
- Define a baseline component contract by category:
|
||||
- Display: `className`, `attributes`
|
||||
- Form: baseline form control props + attrs
|
||||
- Interactive: baseline + JS contract notes
|
||||
|
||||
Consequences/costs:
|
||||
- Requires systematic API audit and staged rollout.
|
||||
|
||||
## 30) Missing Tooling Support for API Misuse
|
||||
|
||||
Problem:
|
||||
- No analyzers/code fixes for common mistakes (invalid variant, unsafe content, missing encoding).
|
||||
|
||||
Why it hurts:
|
||||
- Review burden remains manual.
|
||||
|
||||
Potential solutions:
|
||||
- Introduce Roslyn analyzers for:
|
||||
- magic string validation
|
||||
- unsafe raw HTML from untrusted sources
|
||||
- missing serialization registration patterns
|
||||
|
||||
Consequences/costs:
|
||||
- Initial tooling investment is medium-high.
|
||||
- Scales quality across the codebase after adoption.
|
||||
|
||||
---
|
||||
|
||||
## Cross-Cutting Improvement Patterns
|
||||
|
||||
1. Standardized base options record:
|
||||
- `className`
|
||||
- `attributes`
|
||||
- `testId`
|
||||
- `ariaLabel`
|
||||
|
||||
2. Strong typing for semantic options:
|
||||
- enums/constants/analyzers
|
||||
|
||||
3. Safe content model:
|
||||
- text-safe by default, explicit trusted-html escape hatch
|
||||
|
||||
4. Better docs contract:
|
||||
- every component doc should include:
|
||||
- security notes
|
||||
- accessibility notes
|
||||
- JS dependency notes (if interactive)
|
||||
- extension points
|
||||
|
||||
5. Migration strategy:
|
||||
- additive changes first
|
||||
- obsolete old params
|
||||
- remove deprecated paths in major version bump
|
||||
@@ -0,0 +1,329 @@
|
||||
# Component-by-Component Concerns
|
||||
|
||||
This matrix captures likely API/DX complaints per component area, including potential improvement directions.
|
||||
|
||||
## Display Components
|
||||
|
||||
### Alert
|
||||
|
||||
Concerns:
|
||||
- Variant as magic string.
|
||||
- Content/title may be used as raw HTML without explicit safety boundary.
|
||||
- Custom classes/attributes may be inconsistent.
|
||||
|
||||
Potential improvements:
|
||||
- Enum for variant.
|
||||
- Safe text API + explicit trusted HTML path.
|
||||
- Standard `className` and `attributes`.
|
||||
|
||||
### Avatar
|
||||
|
||||
Concerns:
|
||||
- Fallback/shape/size options can become string-heavy.
|
||||
- Accessibility attributes may be awkward without attr bag.
|
||||
|
||||
Potential improvements:
|
||||
- Typed size/shape options.
|
||||
- Uniform attributes model.
|
||||
|
||||
### Badge
|
||||
|
||||
Concerns:
|
||||
- Variant string typing and typo risk.
|
||||
- Inconsistent extension points compared with Button/Input.
|
||||
|
||||
Potential improvements:
|
||||
- Variant enum/constants.
|
||||
- Standardized extensibility surface.
|
||||
|
||||
### Breadcrumb
|
||||
|
||||
Concerns:
|
||||
- Item model may be primitive/string-only.
|
||||
- Accessibility hooks and custom attrs may be limited.
|
||||
|
||||
Potential improvements:
|
||||
- Named item record model.
|
||||
- Attr bag and aria convenience options.
|
||||
|
||||
### Card
|
||||
|
||||
Concerns:
|
||||
- Raw HTML sections can be misused.
|
||||
- Optional sections create many constructor parameters.
|
||||
|
||||
Potential improvements:
|
||||
- Options record.
|
||||
- Safe content model.
|
||||
|
||||
### Progress
|
||||
|
||||
Concerns:
|
||||
- Value bounds validation may be implicit or absent.
|
||||
- Class extension inconsistencies.
|
||||
|
||||
Potential improvements:
|
||||
- Explicit min/max validation.
|
||||
- Standard class and attr extension.
|
||||
|
||||
### Separator
|
||||
|
||||
Concerns:
|
||||
- Orientation/type as magic string.
|
||||
- Thin API extensibility for accessibility semantics.
|
||||
|
||||
Potential improvements:
|
||||
- Enum for orientation.
|
||||
- Attr bag support.
|
||||
|
||||
### Skeleton
|
||||
|
||||
Concerns:
|
||||
- Shape/sizing patterns vary by caller wrappers.
|
||||
- Lacks compositional guidance for complex placeholders.
|
||||
|
||||
Potential improvements:
|
||||
- Preset variants + className override.
|
||||
- Pattern docs for loading states.
|
||||
|
||||
### Table
|
||||
|
||||
Concerns:
|
||||
- Primitive row/cell string model limits rich content.
|
||||
- Possible heavy constructor precomputation for large data.
|
||||
- Safety boundary unclear when rendering rich cell content.
|
||||
|
||||
Potential improvements:
|
||||
- Typed column/cell models.
|
||||
- Lazy render/cache strategy for large tables.
|
||||
- Explicit text-vs-html cell APIs.
|
||||
|
||||
### Tooltip
|
||||
|
||||
Concerns:
|
||||
- Trigger/content composition can rely on string/slot conventions.
|
||||
- Accessibility and focus behavior may need clearer guidance.
|
||||
|
||||
Potential improvements:
|
||||
- Better keyboard and aria documentation.
|
||||
- Attr/class pass-through consistency.
|
||||
|
||||
## Form Components
|
||||
|
||||
### Button
|
||||
|
||||
Concerns:
|
||||
- Variant/size/type magic strings.
|
||||
- `hxAttrs` raw string ergonomics/security risk.
|
||||
- Need for wrapper to add layout classes in some contexts.
|
||||
|
||||
Potential improvements:
|
||||
- Enums/constants.
|
||||
- Structured attributes.
|
||||
- Standard `className`.
|
||||
|
||||
### Checkbox
|
||||
|
||||
Concerns:
|
||||
- Label/id/checked model may not match other form controls.
|
||||
- Limited pass-through attributes.
|
||||
|
||||
Potential improvements:
|
||||
- Shared form-control options contract.
|
||||
- Attr bag and validation state support.
|
||||
|
||||
### FileInput
|
||||
|
||||
Concerns:
|
||||
- Accepted file types and attrs may be cumbersome.
|
||||
- Inconsistent API vs Input/Textarea.
|
||||
|
||||
Potential improvements:
|
||||
- Shared form-control options.
|
||||
- Better file-specific typed options.
|
||||
|
||||
### Input
|
||||
|
||||
Concerns:
|
||||
- Input type as string.
|
||||
- Validation/aria hooks likely manual.
|
||||
|
||||
Potential improvements:
|
||||
- Input type enum/constants.
|
||||
- Baseline form options and attr bag.
|
||||
|
||||
### RadioGroup
|
||||
|
||||
Concerns:
|
||||
- Tuple options reduce readability.
|
||||
- Direction/layout often string-based.
|
||||
- Attr pass-through likely limited.
|
||||
|
||||
Potential improvements:
|
||||
- Named option record.
|
||||
- Typed direction values.
|
||||
- Standard form/attr contract.
|
||||
|
||||
### Select
|
||||
|
||||
Concerns:
|
||||
- Option model and selected/default semantics may be inconsistent.
|
||||
- Styling/attrs may differ from Input/Textarea.
|
||||
|
||||
Potential improvements:
|
||||
- Named option record.
|
||||
- Unified form control API.
|
||||
|
||||
### Slider
|
||||
|
||||
Concerns:
|
||||
- Value/min/max/step validation and formatting ergonomics.
|
||||
- Limited attr/class extensibility in some usages.
|
||||
|
||||
Potential improvements:
|
||||
- Stronger numeric validation and docs.
|
||||
- Standard extension points.
|
||||
|
||||
### Switch
|
||||
|
||||
Concerns:
|
||||
- Checked/value semantics may differ from checkbox.
|
||||
- JS and accessibility contracts may not be obvious.
|
||||
|
||||
Potential improvements:
|
||||
- Form contract alignment.
|
||||
- Explicit a11y + JS requirements docs.
|
||||
|
||||
### Textarea
|
||||
|
||||
Concerns:
|
||||
- Similar concerns to Input: attrs, validation, and consistency.
|
||||
|
||||
Potential improvements:
|
||||
- Shared baseline form options.
|
||||
|
||||
## Interactive Components
|
||||
|
||||
### Accordion
|
||||
|
||||
Concerns:
|
||||
- Tuple-based item model.
|
||||
- JS selector coupling via markup classes/data attributes.
|
||||
- Rich content safety boundary if strings are HTML.
|
||||
|
||||
Potential improvements:
|
||||
- Named `AccordionItem` model.
|
||||
- Stable data-role contracts.
|
||||
- Explicit safe/trusted content APIs.
|
||||
|
||||
### Calendar
|
||||
|
||||
Concerns:
|
||||
- JS dependency and date contract coupling.
|
||||
- Limited custom attributes for instrumentation/a11y.
|
||||
|
||||
Potential improvements:
|
||||
- Explicit JS contract docs in API comments.
|
||||
- Standard attrs support.
|
||||
|
||||
### CalendarRange
|
||||
|
||||
Concerns:
|
||||
- Similar to Calendar plus complexity around range state.
|
||||
- Validation/error state API may be weak.
|
||||
|
||||
Potential improvements:
|
||||
- Strong state model and docs.
|
||||
- Better attr/validation contract.
|
||||
|
||||
### Dialog
|
||||
|
||||
Concerns:
|
||||
- Open/close semantics rely on data attributes and JS wiring.
|
||||
- Content sections may use raw HTML strings.
|
||||
|
||||
Potential improvements:
|
||||
- Named trigger/actions patterns in docs.
|
||||
- Safe content APIs and structured attrs.
|
||||
|
||||
### DropdownMenu
|
||||
|
||||
Concerns:
|
||||
- Item model can be tuple-heavy.
|
||||
- Keyboard and accessibility behavior depends on JS contract.
|
||||
|
||||
Potential improvements:
|
||||
- Named item/action records.
|
||||
- Explicit interaction/accessibility contract docs.
|
||||
|
||||
### Tabs
|
||||
|
||||
Concerns:
|
||||
- Tuple-based tab definitions.
|
||||
- ID/active state handling as plain strings.
|
||||
- JS contract may be implicit.
|
||||
|
||||
Potential improvements:
|
||||
- `TabItem` record + typed active key model.
|
||||
- Explicit JS and accessibility notes.
|
||||
|
||||
### TimePicker
|
||||
|
||||
Concerns:
|
||||
- Value format/string handling may be error-prone.
|
||||
- JS coupling and validation ergonomics.
|
||||
|
||||
Potential improvements:
|
||||
- Typed time value helpers.
|
||||
- Clear formatting and validation rules.
|
||||
|
||||
## Notification Components
|
||||
|
||||
### Toast
|
||||
|
||||
Concerns:
|
||||
- Trigger lifecycle and JS coupling may not be obvious.
|
||||
- Variant/style options likely string-based.
|
||||
|
||||
Potential improvements:
|
||||
- Typed options and JS contract docs.
|
||||
- Standard attrs/class extension points.
|
||||
|
||||
### ToastViewport
|
||||
|
||||
Concerns:
|
||||
- Placement/config likely string-heavy.
|
||||
- Global singleton usage constraints may be under-documented.
|
||||
|
||||
Potential improvements:
|
||||
- Typed placement/options.
|
||||
- Clear singleton/layout guidance.
|
||||
|
||||
## Navigation Components
|
||||
|
||||
### Pagination
|
||||
|
||||
Concerns:
|
||||
- Data model may be primitive and hard to customize.
|
||||
- Accessibility state semantics need consistency.
|
||||
|
||||
Potential improvements:
|
||||
- Named model for page items and actions.
|
||||
- Strong accessibility defaults and hooks.
|
||||
|
||||
## Cross-Component Cost Notes
|
||||
|
||||
Low-cost improvements:
|
||||
- Better docs for limitations/security/js contracts.
|
||||
- Add design guidelines and migration policy.
|
||||
- Constants for common string literals.
|
||||
|
||||
Medium-cost improvements:
|
||||
- Standard `className` and `attributes` options.
|
||||
- Options records for complex constructors.
|
||||
- Named item models replacing tuples.
|
||||
|
||||
High-cost improvements:
|
||||
- Safe-by-default content model transition.
|
||||
- Full enum migration for all semantic options.
|
||||
- Analyzer suite for API misuse detection.
|
||||
@@ -0,0 +1,51 @@
|
||||
# Component API Design Guidelines
|
||||
|
||||
Use this when creating or evolving components so the API remains predictable.
|
||||
|
||||
## Goals
|
||||
|
||||
- Consistency across all components
|
||||
- Safe defaults for user content
|
||||
- Low ceremony for common use cases
|
||||
- Explicit escape hatches for advanced scenarios
|
||||
|
||||
## Baseline API Conventions
|
||||
|
||||
For every new component, prefer:
|
||||
|
||||
- `className` for caller-supplied Tailwind/CSS classes
|
||||
- `attributes` for arbitrary HTML attributes (`aria-*`, `data-*`, test IDs)
|
||||
- Strongly typed semantic options where practical (enums or constants)
|
||||
- Named item records instead of tuples for complex lists
|
||||
|
||||
## Safety Rules
|
||||
|
||||
1. Plain text input should be encoded by default.
|
||||
2. Raw HTML should require an explicit trusted path.
|
||||
3. Never require callers to manually concatenate unsafe attribute strings for normal usage.
|
||||
|
||||
## Documentation Rules
|
||||
|
||||
Every component doc should include:
|
||||
|
||||
1. Quick example
|
||||
2. All options
|
||||
3. Security notes
|
||||
4. Accessibility notes
|
||||
5. JS dependency notes (if interactive)
|
||||
6. Extension points (`className`, `attributes`)
|
||||
|
||||
## Evolution Rules
|
||||
|
||||
1. Prefer additive changes first.
|
||||
2. Mark old APIs as deprecated with migration examples.
|
||||
3. Remove deprecated paths only in major release.
|
||||
|
||||
## Review Checklist
|
||||
|
||||
- Is the API consistent with sibling components?
|
||||
- Can callers add classes without wrapper divs?
|
||||
- Can callers pass `aria-*` and `data-*` safely?
|
||||
- Are semantic options type-safe?
|
||||
- Are user-provided strings encoded by default?
|
||||
- Are interactive JS requirements documented?
|
||||
@@ -0,0 +1,128 @@
|
||||
# Component API Limitations and Workarounds
|
||||
|
||||
This page documents known limitations in the current component API and practical ways to work effectively with them.
|
||||
|
||||
## 1) Magic String Parameters
|
||||
|
||||
Limitation:
|
||||
- Semantic options like `variant`, `size`, and similar values are frequently string-based.
|
||||
|
||||
What this means:
|
||||
- Typos may silently fall back to defaults.
|
||||
|
||||
Workaround:
|
||||
- Centralize repeated literals in local constants in your feature code.
|
||||
- Prefer named arguments for readability.
|
||||
|
||||
Example:
|
||||
|
||||
```csharp
|
||||
private const string VariantDestructive = "destructive";
|
||||
|
||||
var deleteButton = new Button(
|
||||
label: "Delete",
|
||||
variant: VariantDestructive,
|
||||
size: "sm");
|
||||
```
|
||||
|
||||
## 2) Extra Styling Often Requires Wrappers
|
||||
|
||||
Limitation:
|
||||
- Not every component exposes a class extension parameter.
|
||||
|
||||
What this means:
|
||||
- You may need wrapper elements for layout spacing, sizing, or responsive behavior.
|
||||
|
||||
Workaround:
|
||||
- Use a minimal wrapper pattern and keep wrapper intent obvious.
|
||||
|
||||
Example:
|
||||
|
||||
```html
|
||||
<div class="md:max-w-sm w-full">$$SaveButton$$</div>
|
||||
```
|
||||
|
||||
## 3) No Universal Attribute Bag
|
||||
|
||||
Limitation:
|
||||
- Some components expose `hxAttrs`, some do not, and no shared attributes model exists yet.
|
||||
|
||||
What this means:
|
||||
- Passing `aria-*`, `data-*`, or test selectors is inconsistent.
|
||||
|
||||
Workaround:
|
||||
- Prefer wrapper-level attributes where possible.
|
||||
- If using raw attr strings, keep them static and explicit.
|
||||
|
||||
## 4) No Direct "Props in .htmx Markup" Model
|
||||
|
||||
Limitation:
|
||||
- Component/page parameterization is constructor-driven in `.htmx.cs`, not inline-props driven in `.htmx` markup.
|
||||
|
||||
What this means:
|
||||
- Dynamic behavior is assembled in C# code-behind.
|
||||
|
||||
Workaround:
|
||||
- Treat `.htmx` as shape and slot layout.
|
||||
- Treat `.htmx.cs` as the single source of component input logic.
|
||||
|
||||
## 5) Raw HTML Output Requires Discipline
|
||||
|
||||
Limitation:
|
||||
- Several components render provided strings as HTML.
|
||||
|
||||
What this means:
|
||||
- User input must be encoded before rendering.
|
||||
|
||||
Workaround:
|
||||
- Always encode user-provided values before `ToUtf8Bytes()`.
|
||||
|
||||
Example:
|
||||
|
||||
```csharp
|
||||
var safeName = System.Web.HttpUtility.HtmlEncode(userDisplayName);
|
||||
_nameData = safeName.ToUtf8Bytes();
|
||||
```
|
||||
|
||||
## 6) Interactive Components Depend on JS Contracts
|
||||
|
||||
Limitation:
|
||||
- Components like tabs, accordion, dialog, calendar, and toast depend on JavaScript hooks/selectors.
|
||||
|
||||
What this means:
|
||||
- Markup can render but behave incorrectly if expected JS wiring is missing.
|
||||
|
||||
Workaround:
|
||||
- Verify behavior after HTMX swaps.
|
||||
- Keep required data-role/class markers intact.
|
||||
|
||||
## 7) Tuple APIs for Complex Components
|
||||
|
||||
Limitation:
|
||||
- Some components expect tuple arrays for items/options.
|
||||
|
||||
What this means:
|
||||
- Call sites can become harder to read and evolve.
|
||||
|
||||
Workaround:
|
||||
- Build small local records/variables first, then map to tuples.
|
||||
|
||||
## 8) Form API Inconsistency
|
||||
|
||||
Limitation:
|
||||
- Form primitives do not all expose the same extension points.
|
||||
|
||||
What this means:
|
||||
- You need per-component familiarity.
|
||||
|
||||
Workaround:
|
||||
- Create feature-local helper methods to normalize usage patterns.
|
||||
|
||||
## 9) Recommendation for Teams
|
||||
|
||||
If multiple developers are contributing:
|
||||
|
||||
1. Define local conventions for allowed variant strings.
|
||||
2. Standardize wrapper patterns (`layout wrappers`, `a11y wrappers`, `test-id wrappers`).
|
||||
3. Review for HTML encoding whenever user input is rendered.
|
||||
4. Track repeated pain points in docs/Issues for future API upgrades.
|
||||
@@ -0,0 +1,68 @@
|
||||
# Improvement Options and Costs
|
||||
|
||||
This matrix helps prioritize API improvements by DX value, risk, and migration cost.
|
||||
|
||||
Legend:
|
||||
|
||||
- Effort: S (small), M (medium), L (large), XL (very large)
|
||||
- Break Risk: Low, Medium, High
|
||||
- Runtime Impact: Positive, Neutral, Slight Negative
|
||||
|
||||
| Proposal | Solves | Effort | Break Risk | Runtime Impact | Notes |
|
||||
|---|---|---|---|---|---|
|
||||
| Add standardized `className` to all components | wrapper-div workaround, styling consistency | M | Low | Neutral | Additive change if optional |
|
||||
| Add standardized attributes bag (`attributes`) | missing `aria-*`, `data-*`, test IDs | L | Medium | Slight Negative | Best long-term extensibility |
|
||||
| Keep `hxAttrs` as compatibility fallback | migration safety | S | Low | Neutral | Mark as legacy in docs |
|
||||
| Enums for variant/size/type | magic strings | M | Medium | Neutral | Better compile-time safety |
|
||||
| Constants classes for allowed string values | magic strings (partial) | S | Low | Neutral | Good transitional step |
|
||||
| Replace tuple APIs with named records | readability, future extensibility | M | Medium | Neutral | `TabItem`, `AccordionItem`, etc. |
|
||||
| Add options-record constructors for complex components | constructor bloat | M | Low | Neutral | Improves call-site clarity |
|
||||
| Safe-by-default text encoding APIs | XSS risk | M | High | Neutral | Breaking if current raw HTML behavior is relied on |
|
||||
| Explicit trusted HTML wrapper API | intentional raw HTML path | M | Medium | Neutral | Clear security intent |
|
||||
| Add standardized Security section in every component doc | security docs inconsistency | M | Low | Neutral | High ROI docs work |
|
||||
| Add standardized Accessibility section in every component doc | a11y gaps | M | Low | Neutral | High ROI docs work |
|
||||
| Add JS contract metadata/docs for interactive components | hidden JS dependencies | S | Low | Neutral | Immediate debugging benefit |
|
||||
| Add development-time JS diagnostics in components.js | silent interactive failures | M | Low | Slight Negative | Dev-only checks recommended |
|
||||
| Add analyzer: invalid variant literals | magic string typos | L | Low | Neutral | Tooling investment pays off |
|
||||
| Add analyzer: unsafe unencoded user input usage | XSS prevention | L | Medium | Neutral | Requires careful heuristics |
|
||||
| Add API evolution policy and deprecation plan | change management | S | Low | Neutral | Needed before major refactors |
|
||||
| Introduce per-category baseline contracts | inconsistency across components | L | Medium | Neutral | Strategic but broad |
|
||||
| Introduce table column/cell model | table API limitations | L | Medium | Neutral | High payoff for real apps |
|
||||
| Add form control baseline contract | form component inconsistency | L | Medium | Neutral | Improves predictability |
|
||||
| Introduce lazy compute in heavy components | precompute allocation concerns | M | Low | Positive | Benchmark before and after |
|
||||
|
||||
## Recommended Sequencing
|
||||
|
||||
1. Documentation-first, no-break improvements:
|
||||
- known limitations docs
|
||||
- security/a11y/js contract sections
|
||||
- issue tracker links and migration guidance
|
||||
|
||||
2. Additive API upgrades:
|
||||
- `className`
|
||||
- `attributes`
|
||||
- options records
|
||||
- constants for allowed values
|
||||
|
||||
3. Strong typing and validation:
|
||||
- enums
|
||||
- analyzers
|
||||
- debug validations
|
||||
|
||||
4. Breaking/security-hardening updates:
|
||||
- safe-by-default content model
|
||||
- deprecate raw string HTML entry points
|
||||
|
||||
## Consequence Summary
|
||||
|
||||
Positive consequences:
|
||||
- More predictable and discoverable API
|
||||
- Lower bug rate from string typos and attr mistakes
|
||||
- Better security baseline
|
||||
- Less wrapper-div boilerplate
|
||||
|
||||
Negative/neutral consequences:
|
||||
- Larger API surface
|
||||
- Migration overhead in existing usages
|
||||
- Potentially more allocations for flexible attribute models
|
||||
- Need for contributor discipline to maintain consistency
|
||||
@@ -0,0 +1,30 @@
|
||||
# Issues and API Improvement Tracker
|
||||
|
||||
This folder tracks known design/API smells in the current template stack, with proposed fixes and their trade-offs.
|
||||
|
||||
Use this section for:
|
||||
|
||||
- Capturing developer pain points before they are forgotten
|
||||
- Aligning on possible API improvements
|
||||
- Comparing implementation cost vs DX benefit
|
||||
- Planning staged, low-risk migrations
|
||||
|
||||
## Files
|
||||
|
||||
- `Component-API-Smells.md` - exhaustive problem catalog and solution options
|
||||
- `Improvement-Options-and-Costs.md` - decision matrix with cost/consequence analysis
|
||||
- `Roadmap.md` - phased adoption plan
|
||||
- `Component-by-Component-Concerns.md` - component-level complaint inventory and improvements
|
||||
- `Components/00-API-Limitations-and-Workarounds.md` - component API limitations and practical workarounds
|
||||
- `Components/00-API-Design-Guidelines.md` - component API design principles for future changes
|
||||
|
||||
## Scope
|
||||
|
||||
This is intentionally broader than bug tracking. Many entries are not defects; they are DX and API design weaknesses (inconsistency, discoverability, ergonomics, safety defaults, and maintainability concerns).
|
||||
|
||||
## Ground Rules
|
||||
|
||||
1. Keep issues concrete and reproducible.
|
||||
2. Include at least one realistic solution.
|
||||
3. Always state consequences (breaking change risk, complexity, perf, AOT constraints).
|
||||
4. Prefer incremental migration paths over large rewrites.
|
||||
@@ -0,0 +1,81 @@
|
||||
# API Improvement Roadmap
|
||||
|
||||
This roadmap is designed to improve DX without destabilizing the current template.
|
||||
|
||||
## Phase 0: Track and Communicate (Now)
|
||||
|
||||
Goals:
|
||||
- Make limitations explicit.
|
||||
- Prevent repeated confusion.
|
||||
|
||||
Actions:
|
||||
- Publish issues catalog and cost matrix.
|
||||
- Link issues from the main component reference.
|
||||
- Add "Known Limitations" + "Security" notes in component docs.
|
||||
|
||||
Success criteria:
|
||||
- New contributors can find limitations before implementation.
|
||||
|
||||
## Phase 1: Low-Risk Additive API Improvements
|
||||
|
||||
Goals:
|
||||
- Improve ergonomics with minimal break risk.
|
||||
|
||||
Actions:
|
||||
- Add optional `className` to all components.
|
||||
- Add optional `attributes` bag to all components.
|
||||
- Keep `hxAttrs` as legacy fallback.
|
||||
- Introduce constants classes for common string domains.
|
||||
|
||||
Success criteria:
|
||||
- Most wrapper-div style workarounds disappear.
|
||||
- Most custom attribute hacks disappear.
|
||||
|
||||
## Phase 2: Standardization and Strong Typing
|
||||
|
||||
Goals:
|
||||
- Reduce error-prone string APIs.
|
||||
|
||||
Actions:
|
||||
- Move high-value components to enums for semantic options.
|
||||
- Introduce options records where constructors are overloaded.
|
||||
- Replace tuple-based list inputs with named records.
|
||||
|
||||
Success criteria:
|
||||
- IntelliSense can guide common component usage.
|
||||
- Fewer runtime surprises from typos.
|
||||
|
||||
## Phase 3: Security and Validation Hardening
|
||||
|
||||
Goals:
|
||||
- Safer defaults and clearer intent.
|
||||
|
||||
Actions:
|
||||
- Introduce safe-by-default text paths.
|
||||
- Keep explicit trusted HTML APIs for advanced usage.
|
||||
- Add analyzers (or debug validators) for invalid options and unsafe patterns.
|
||||
|
||||
Success criteria:
|
||||
- XSS risk materially reduced.
|
||||
- Unsafe usage becomes explicit and reviewable.
|
||||
|
||||
## Phase 4: Deep API Evolution
|
||||
|
||||
Goals:
|
||||
- Improve advanced composition and maintainability.
|
||||
|
||||
Actions:
|
||||
- Formalize per-category component contracts.
|
||||
- Improve table/form models for richer data and validation scenarios.
|
||||
- Consider generator-level support for richer parameter/props models.
|
||||
|
||||
Success criteria:
|
||||
- New component additions follow one predictable design style.
|
||||
- Complex UIs require less custom glue code.
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
1. Add new APIs first.
|
||||
2. Mark old parameters/patterns as deprecated.
|
||||
3. Provide codemod or migration examples.
|
||||
4. Remove deprecated surface only in major release.
|
||||
Reference in New Issue
Block a user