950 lines
24 KiB
Markdown
950 lines
24 KiB
Markdown
# Module 11: Conceptual Specifications
|
|
|
|
## Lesson 3: Element & State Specifications
|
|
|
|
**Deep dive on Layers 4 & 5 — Complete implementation details**
|
|
|
|
---
|
|
|
|
## The Final Layers
|
|
|
|
You've specified pages, sections, and widgets. Now you document the details that developers implement:
|
|
|
|
- **Layer 4: Cards** — Content grouping patterns
|
|
- **Layer 5: Elements** — Individual UI pieces with complete state coverage
|
|
|
|
These are the most detailed specifications. Get them right, and developers build exactly what you envisioned.
|
|
|
|
---
|
|
|
|
## Card-Level Specifications (Layer 4)
|
|
|
|
Cards group related content into repeatable patterns.
|
|
|
|
### What Cards Define
|
|
|
|
```
|
|
Widget-Level: "Task list widget displays user tasks"
|
|
↓
|
|
Card-Level: "Each task card shows title, assignee,
|
|
due date, status, and action buttons"
|
|
```
|
|
|
|
Cards answer:
|
|
- **What content pattern does this represent?**
|
|
- **What data structure feeds it?**
|
|
- **How many instances appear?**
|
|
- **Is it interactive?**
|
|
|
|
---
|
|
|
|
## Card Specification Pattern
|
|
|
|
```markdown
|
|
## Card: [Card Name]
|
|
**ID:** [Parent-ID]-[Card-ID]
|
|
|
|
### Purpose
|
|
[What this card displays/represents]
|
|
|
|
### Data Structure
|
|
[Schema or data shape that feeds this card]
|
|
|
|
### Instances
|
|
[Single/Template/Fixed count]
|
|
|
|
### Interaction
|
|
[Static/Clickable/Expandable/Draggable]
|
|
|
|
### States
|
|
[If interactive, document states]
|
|
|
|
### Content Slots
|
|
[What content areas exist]
|
|
|
|
### Layout
|
|
[Visual arrangement of elements]
|
|
|
|
### Contains
|
|
[List child elements]
|
|
```
|
|
|
|
---
|
|
|
|
## Card Example: Task Card
|
|
|
|
```markdown
|
|
## Card: Task Card
|
|
**ID:** W01-C01-task-card
|
|
|
|
### Purpose
|
|
Display one task with key information and actions.
|
|
Allow quick status updates and task access.
|
|
|
|
### Data Structure
|
|
```json
|
|
{
|
|
"id": "string (UUID)",
|
|
"title": "string (max 100 chars)",
|
|
"assignee": {
|
|
"id": "string",
|
|
"name": "string",
|
|
"avatar": "string (URL)"
|
|
},
|
|
"dueDate": "ISO 8601 date string",
|
|
"status": "enum (pending|in_progress|completed)",
|
|
"priority": "enum (low|medium|high)"
|
|
}
|
|
```
|
|
|
|
### Instances
|
|
Template card, rendered once per task (dynamic count)
|
|
|
|
### Interaction
|
|
- Clickable: Yes (entire card navigates to task detail)
|
|
- Expandable: No
|
|
- Draggable: Yes (for reordering in list)
|
|
|
|
### States
|
|
- Default: White background, normal text
|
|
- Hover: Light gray background (#F3F4F6)
|
|
- Pressed: Slight scale down (0.98)
|
|
- Dragging: Lifted appearance (shadow), slightly rotated
|
|
- Overdue: Red accent border when past due date
|
|
- Completed: Strikethrough title, muted colors
|
|
|
|
### Content Slots
|
|
- Priority indicator (left edge, colored bar)
|
|
- Title text
|
|
- Assignee avatar + name
|
|
- Due date
|
|
- Status badge
|
|
- Quick action menu (three dots, right edge)
|
|
|
|
### Layout
|
|
```
|
|
┌────────────────────────────────────┐
|
|
│ ┃ [Title Text] [•••] │
|
|
│ ┃ │
|
|
│ ┃ [👤 Assignee] [📅 Date] [●] │
|
|
└────────────────────────────────────┘
|
|
↑ ↑
|
|
Priority Status
|
|
```
|
|
|
|
### Contains
|
|
- E01: Priority Bar
|
|
- E02: Task Title
|
|
- E03: Assignee Avatar
|
|
- E04: Assignee Name
|
|
- E05: Due Date Label
|
|
- E06: Status Badge
|
|
- E07: Action Menu Button
|
|
```
|
|
|
|
---
|
|
|
|
## Card Example: Feature Card
|
|
|
|
```markdown
|
|
## Card: Feature Card
|
|
**ID:** P01-S04-C01-feature-card
|
|
|
|
### Purpose
|
|
Highlight one product feature to build trust before signup.
|
|
|
|
### Data Structure
|
|
```json
|
|
{
|
|
"icon": "string (icon identifier)",
|
|
"title": "string (max 50 chars)",
|
|
"description": "string (max 120 chars)"
|
|
}
|
|
```
|
|
|
|
### Instances
|
|
Template, rendered 3 times with fixed data
|
|
|
|
### Interaction
|
|
Static (not clickable)
|
|
|
|
### States
|
|
N/A (no interactive states)
|
|
|
|
### Content Slots
|
|
- Icon (centered, 48x48px)
|
|
- Title (centered, h3)
|
|
- Description (centered, body text)
|
|
|
|
### Layout
|
|
```
|
|
┌─────────────────┐
|
|
│ │
|
|
│ [Icon] │
|
|
│ │
|
|
│ Feature Title │
|
|
│ │
|
|
│ Description │
|
|
│ text goes │
|
|
│ here │
|
|
│ │
|
|
└─────────────────┘
|
|
```
|
|
|
|
### Contains
|
|
- E01: Feature Icon
|
|
- E02: Feature Title
|
|
- E03: Feature Description
|
|
```
|
|
|
|
---
|
|
|
|
## Element-Level Specifications (Layer 5)
|
|
|
|
Elements are the atomic UI pieces: buttons, inputs, labels, icons.
|
|
|
|
### What Elements Define
|
|
|
|
```
|
|
Card-Level: "Task card contains title, assignee, status"
|
|
↓
|
|
Element-Level: "Status badge has 3 states: pending (gray),
|
|
in_progress (blue), completed (green),
|
|
with specific text and aria-label for each"
|
|
```
|
|
|
|
Elements answer:
|
|
- **What are ALL possible states?**
|
|
- **What is the EXACT content?**
|
|
- **What ARIA attributes apply?**
|
|
- **How does it behave on interaction?**
|
|
- **What are the translations?**
|
|
|
|
---
|
|
|
|
## Element Specification Pattern
|
|
|
|
```markdown
|
|
## Element: [Element Name]
|
|
**ID:** [Full-Hierarchy-ID]
|
|
|
|
### Type
|
|
[Button/Input/Label/Icon/Link/Text/etc.]
|
|
|
|
### States
|
|
[Every possible state with complete description]
|
|
|
|
### Content
|
|
- Label: "[Exact text]"
|
|
- Placeholder: "[Exact text if applicable]"
|
|
- Translations: [All supported languages]
|
|
|
|
### ARIA
|
|
[All ARIA attributes for each state]
|
|
|
|
### Behavior
|
|
[What happens on interaction]
|
|
|
|
### Visual
|
|
[Colors, sizes, spacing if critical to specification]
|
|
```
|
|
|
|
---
|
|
|
|
## Element Example: Submit Button
|
|
|
|
```markdown
|
|
## Element: Submit Button
|
|
**ID:** P01-S03-W01-E05-submit-button
|
|
|
|
### Type
|
|
Button (primary action)
|
|
|
|
### States
|
|
|
|
#### Default
|
|
- Label: "Create Free Account"
|
|
- Appearance: Blue background (#2563EB), white text
|
|
- Cursor: Pointer
|
|
- Enabled: Yes
|
|
- aria-disabled: "false"
|
|
|
|
#### Hover
|
|
- Appearance: Darker blue (#1E40AF)
|
|
- Transition: 150ms ease
|
|
- Everything else: Same as default
|
|
|
|
#### Active (pressed)
|
|
- Appearance: Even darker blue (#1E3A8A)
|
|
- Scale: 0.98 (slight press effect)
|
|
|
|
#### Disabled
|
|
- Label: "Create Free Account"
|
|
- Appearance: Gray background (#D1D5DB), gray text (#6B7280)
|
|
- Cursor: Not-allowed
|
|
- Enabled: No
|
|
- aria-disabled: "true"
|
|
- Reason: Form validation incomplete
|
|
|
|
#### Loading
|
|
- Label: [Hidden, replaced by spinner]
|
|
- Appearance: Blue background, spinner centered
|
|
- Cursor: Wait
|
|
- Enabled: No (can't click during submit)
|
|
- aria-busy: "true"
|
|
- aria-label: "Creating account, please wait"
|
|
|
|
#### Success (brief)
|
|
- Label: [Hidden, replaced by checkmark ✓]
|
|
- Appearance: Green background (#10B981)
|
|
- Duration: 1.5s visible, then redirect
|
|
- aria-label: "Account created successfully"
|
|
|
|
#### Error (server error)
|
|
- Returns to Default state
|
|
- Error message appears above form (not on button)
|
|
|
|
### Content
|
|
|
|
**English:**
|
|
- Label: "Create Free Account"
|
|
- Loading: aria-label "Creating account, please wait"
|
|
- Success: aria-label "Account created successfully"
|
|
|
|
**Spanish:**
|
|
- Label: "Crear Cuenta Gratuita"
|
|
- Loading: aria-label "Creando cuenta, por favor espere"
|
|
- Success: aria-label "Cuenta creada exitosamente"
|
|
|
|
**German:**
|
|
- Label: "Kostenloses Konto erstellen"
|
|
- Loading: aria-label "Konto wird erstellt, bitte warten"
|
|
- Success: aria-label "Konto erfolgreich erstellt"
|
|
|
|
### ARIA
|
|
|
|
**Default/Hover/Active:**
|
|
- role: "button" (implicit from <button>)
|
|
- type: "submit"
|
|
- aria-label: Not needed (label is visible)
|
|
- aria-disabled: "false"
|
|
|
|
**Disabled:**
|
|
- aria-disabled: "true"
|
|
- aria-describedby: Points to validation error if specific reason
|
|
|
|
**Loading:**
|
|
- aria-busy: "true"
|
|
- aria-label: "Creating account, please wait"
|
|
- aria-live: "polite" (announces state change)
|
|
|
|
**Success:**
|
|
- aria-label: "Account created successfully"
|
|
- aria-live: "polite" (announces success)
|
|
|
|
### Behavior
|
|
|
|
**On Click (when enabled):**
|
|
1. Trigger form validation
|
|
2. If invalid: Prevent submit, focus first error field
|
|
3. If valid: Change to Loading state
|
|
4. Submit form data to server
|
|
5. On success response: Change to Success state (1.5s), then redirect
|
|
6. On error response: Return to Default, show error message above form
|
|
|
|
**On Enter key (when focused):**
|
|
Same as click behavior
|
|
|
|
### Visual
|
|
- Height: 48px (comfortable touch target)
|
|
- Width: 100% of form width (mobile), min 200px (desktop)
|
|
- Border radius: 8px
|
|
- Font: 16px, semi-bold
|
|
- Padding: 12px 24px
|
|
```
|
|
|
|
---
|
|
|
|
## Element Example: Email Input Field
|
|
|
|
```markdown
|
|
## Element: Email Input Field
|
|
**ID:** P01-S03-W01-E01-email-field
|
|
|
|
### Type
|
|
Text input (email)
|
|
|
|
### States
|
|
|
|
#### Default (empty)
|
|
- Placeholder: "you@example.com"
|
|
- Border: 1px gray (#D1D5DB)
|
|
- Background: White
|
|
- Label: "Email" (above field)
|
|
- Value: ""
|
|
- aria-invalid: "false"
|
|
|
|
#### Focused (user clicks in)
|
|
- Border: 2px blue (#2563EB)
|
|
- Placeholder: Fades to 50% opacity
|
|
- Focus ring: 2px blue outline, 2px offset
|
|
- All else: Same as default
|
|
|
|
#### Typing (user entering text)
|
|
- Shows typed characters
|
|
- Placeholder: Hidden
|
|
- Validation: Not yet triggered
|
|
- All else: Same as focused
|
|
|
|
#### Valid (after blur, email format correct)
|
|
- Border: 1px green (#10B981)
|
|
- Success icon: Green checkmark appears (right side)
|
|
- aria-invalid: "false"
|
|
- All else: Same as default
|
|
|
|
#### Invalid - Format (after blur, email format incorrect)
|
|
- Border: 2px red (#DC2626)
|
|
- Error message: "Please enter a valid email address" (below field)
|
|
- Error icon: Red X appears (right side)
|
|
- aria-invalid: "true"
|
|
- aria-describedby: "email-error"
|
|
|
|
#### Invalid - Taken (async check, email already registered)
|
|
- Border: 2px red (#DC2626)
|
|
- Error message: "This email is already registered. [Log in instead →]" (below field)
|
|
- Error icon: Red X appears
|
|
- aria-invalid: "true"
|
|
- aria-describedby: "email-error"
|
|
- Link: "Log in instead" navigates to login page
|
|
|
|
#### Disabled (during form submission)
|
|
- Background: Light gray (#F3F4F6)
|
|
- Text: Gray (#6B7280)
|
|
- Cursor: Not-allowed
|
|
- Editable: No
|
|
- aria-disabled: "true"
|
|
|
|
### Content
|
|
|
|
**English:**
|
|
- Label: "Email"
|
|
- Placeholder: "you@example.com"
|
|
- Error (format): "Please enter a valid email address"
|
|
- Error (taken): "This email is already registered. [Log in instead →]"
|
|
- Helper text: None
|
|
|
|
**Spanish:**
|
|
- Label: "Correo electrónico"
|
|
- Placeholder: "tu@ejemplo.com"
|
|
- Error (format): "Por favor, introduce una dirección de correo válida"
|
|
- Error (taken): "Este correo ya está registrado. [Iniciar sesión →]"
|
|
|
|
**German:**
|
|
- Label: "E-Mail"
|
|
- Placeholder: "du@beispiel.com"
|
|
- Error (format): "Bitte geben Sie eine gültige E-Mail-Adresse ein"
|
|
- Error (taken): "Diese E-Mail ist bereits registriert. [Anmelden →]"
|
|
|
|
### ARIA
|
|
|
|
**Default:**
|
|
- role: "textbox" (implicit)
|
|
- type: "email"
|
|
- id: "email-field"
|
|
- aria-label: "Email address for your account"
|
|
- aria-required: "true"
|
|
- aria-invalid: "false"
|
|
- autocomplete: "email"
|
|
|
|
**Invalid:**
|
|
- aria-invalid: "true"
|
|
- aria-describedby: "email-error"
|
|
- Error element: id="email-error", role="alert"
|
|
|
|
**Disabled:**
|
|
- aria-disabled: "true"
|
|
|
|
### Behavior
|
|
|
|
**On Focus:**
|
|
- Border becomes blue
|
|
- Placeholder fades
|
|
- Cursor appears in field
|
|
|
|
**On Blur (user leaves field):**
|
|
1. Validate email format (regex check)
|
|
2. If invalid format: Show format error
|
|
3. If valid format: Start async check (debounced 1s)
|
|
4. Async check: Verify email not already registered
|
|
5. If taken: Show "already registered" error with login link
|
|
6. If available: Show green checkmark
|
|
|
|
**On Change (while typing):**
|
|
- Real-time character entry
|
|
- No validation until blur (except clearing previous errors)
|
|
|
|
**On Paste:**
|
|
- Accept pasted text
|
|
- Trigger validation after paste completes
|
|
|
|
### Visual
|
|
- Height: 48px
|
|
- Width: 100% of form width
|
|
- Border radius: 8px
|
|
- Font: 16px (prevents zoom on iOS)
|
|
- Padding: 12px 16px
|
|
- Error message: 14px, red (#DC2626), 4px below field
|
|
```
|
|
|
|
---
|
|
|
|
## All States Matter
|
|
|
|
Every element needs complete state documentation:
|
|
|
|
### Button States Checklist
|
|
|
|
- [ ] Default
|
|
- [ ] Hover
|
|
- [ ] Active (pressed)
|
|
- [ ] Focused (keyboard navigation)
|
|
- [ ] Disabled
|
|
- [ ] Loading
|
|
- [ ] Success (if applicable)
|
|
- [ ] Error (if applicable)
|
|
|
|
### Input States Checklist
|
|
|
|
- [ ] Default (empty)
|
|
- [ ] Focused
|
|
- [ ] Typing
|
|
- [ ] Valid
|
|
- [ ] Invalid (with all error types)
|
|
- [ ] Disabled
|
|
- [ ] Read-only (if applicable)
|
|
|
|
### Link States Checklist
|
|
|
|
- [ ] Default
|
|
- [ ] Hover
|
|
- [ ] Active (pressed)
|
|
- [ ] Visited (if applicable)
|
|
- [ ] Focused
|
|
|
|
**The rule: If developers might ask "What happens when...", you need a state for it.**
|
|
|
|
---
|
|
|
|
## Edge Cases
|
|
|
|
Document what happens when things go wrong or unusual:
|
|
|
|
```markdown
|
|
## Edge Cases for Form Submission
|
|
|
|
### Email Already Exists
|
|
- **Trigger:** Server returns 409 Conflict
|
|
- **Display:** Error below email field: "This email is already registered. [Log in instead →]"
|
|
- **Action:** Link navigates to login page
|
|
- **Recovery:** User can try different email or click link to login
|
|
- **State:** Form re-enabled, focus stays on email field
|
|
|
|
### Network Error
|
|
- **Trigger:** Request times out (>10s) or connection fails
|
|
- **Display:** Error banner above form: "Connection lost. Your data is saved."
|
|
- **Action:** [Retry] button appears
|
|
- **Recovery:** Click Retry resubmits with same data (not lost)
|
|
- **State:** Form re-enabled
|
|
|
|
### Rate Limited
|
|
- **Trigger:** Too many signup attempts from IP
|
|
- **Display:** Error banner: "Too many attempts. Try again in 5 minutes."
|
|
- **Action:** Countdown timer visible (5:00, 4:59, 4:58...)
|
|
- **Recovery:** Wait for timer, form re-enables when timer expires
|
|
- **State:** Form disabled during countdown
|
|
|
|
### Browser Back Button During Submit
|
|
- **Trigger:** User clicks browser back while form is submitting
|
|
- **Display:** Browser confirms: "Are you sure? Form submission in progress."
|
|
- **Recovery:** If user proceeds back, request is cancelled
|
|
- **State:** Form data lost (unless browser preserves it)
|
|
|
|
### JavaScript Disabled
|
|
- **Trigger:** User has JavaScript disabled
|
|
- **Display:** Form still renders, no client-side validation
|
|
- **Behavior:** Server-side validation handles everything
|
|
- **Recovery:** Server returns page with errors highlighted
|
|
- **State:** Progressive enhancement - works without JS
|
|
```
|
|
|
|
---
|
|
|
|
## Empty States
|
|
|
|
Every collection can be empty. Document what users see:
|
|
|
|
```markdown
|
|
## Task List Empty State
|
|
|
|
**When:** User has no tasks assigned
|
|
|
|
**Display:**
|
|
- Illustration: Simple line drawing of empty checklist
|
|
- Headline: "No tasks yet"
|
|
- Subtext: "Tasks will appear here when they're assigned to you"
|
|
- Action: [Browse all household tasks] button
|
|
- Alternative: If user can create tasks: [Create your first task] button
|
|
|
|
**Why:** Reduces confusion, sets expectation, provides next action
|
|
|
|
**Visual:**
|
|
```
|
|
┌─────────────────────────────────┐
|
|
│ │
|
|
│ [Empty │
|
|
│ checklist │
|
|
│ illustration] │
|
|
│ │
|
|
│ No tasks yet │
|
|
│ │
|
|
│ Tasks will appear here when │
|
|
│ they're assigned to you │
|
|
│ │
|
|
│ [Browse all household tasks] │
|
|
│ │
|
|
└─────────────────────────────────┘
|
|
```
|
|
|
|
**ARIA:**
|
|
- Container: role="status" (announces to screen readers)
|
|
- aria-label: "No tasks assigned"
|
|
```
|
|
|
|
---
|
|
|
|
## Loading States
|
|
|
|
Document what users see while data loads:
|
|
|
|
```markdown
|
|
## Dashboard Loading State
|
|
|
|
**Duration:** Typically 0-3 seconds
|
|
|
|
**Skeleton Structure:**
|
|
- Header: Static (user info visible, loaded from auth)
|
|
- Task section: 3 skeleton cards (gray shimmer rectangles)
|
|
- Calendar section: Skeleton grid matching final layout
|
|
- Sidebar: Skeleton menu items
|
|
|
|
**Animation:**
|
|
- Shimmer effect: Light sweep left-to-right
|
|
- Duration: 1.5s loop
|
|
- Color: Gray (#E5E7EB) to lighter gray (#F3F4F6)
|
|
|
|
**Fallback:**
|
|
- If loading exceeds 5 seconds: Show "Taking longer than expected..."
|
|
- Action: [Refresh] button appears
|
|
- Why: Network issue or slow connection
|
|
|
|
**Error State:**
|
|
- If load fails: "Couldn't load dashboard"
|
|
- Message: "Something went wrong. Please try again."
|
|
- Action: [Retry] button
|
|
- Alternative: "If problem persists, [contact support]"
|
|
|
|
**Visual Comparison:**
|
|
|
|
```
|
|
LOADING LOADED
|
|
┌────────────────────┐ ┌────────────────────┐
|
|
│ ▓▓▓▓▓▓▓▓▓▓ │ │ Walk Max at 3pm │
|
|
│ ▓▓▓▓ │ │ Assigned: Alice │
|
|
│ │ │ Due: Today │
|
|
├────────────────────┤ ├────────────────────┤
|
|
│ ▓▓▓▓▓▓▓▓▓▓ │ │ Buy dog food │
|
|
│ ▓▓▓▓ │ │ Assigned: Bob │
|
|
│ │ │ Due: Tomorrow │
|
|
└────────────────────┘ └────────────────────┘
|
|
```
|
|
|
|
**Accessibility:**
|
|
- aria-busy="true" on loading container
|
|
- aria-live="polite" announces when loaded
|
|
- Screen reader: "Loading tasks..." → "3 tasks loaded"
|
|
```
|
|
|
|
---
|
|
|
|
## Content Specifications
|
|
|
|
Go beyond just listing text. Specify tone, constraints, and variations:
|
|
|
|
```markdown
|
|
## Error Message Content Standards
|
|
|
|
### Tone
|
|
- Helpful, not blaming
|
|
- Use "Please" for requests
|
|
- Avoid "Invalid", "Error", "Wrong"
|
|
- Offer solutions when possible
|
|
|
|
### Format
|
|
- Sentence case (not ALL CAPS)
|
|
- Period at end if complete sentence
|
|
- No period if fragment
|
|
- Link format: [Action text →]
|
|
|
|
### Validation Error Table
|
|
|
|
| Field | Condition | Message | Link |
|
|
|-------|-----------|---------|------|
|
|
| Email | Empty | "Email is required" | None |
|
|
| Email | Invalid format | "Please enter a valid email address" | None |
|
|
| Email | Already exists | "This email is already registered." | [Log in instead →] |
|
|
| Password | Empty | "Password is required" | None |
|
|
| Password | Too short | "Password must be at least 8 characters" | None |
|
|
| Password | No number | "Include at least one number" | None |
|
|
| Name | Empty | "Name is required" | None |
|
|
| Name | Too long | "Name must be under 50 characters" | None |
|
|
|
|
### System Error Messages
|
|
|
|
| Scenario | Message | Action |
|
|
|----------|---------|--------|
|
|
| Network timeout | "Connection lost. Your data is saved." | [Retry] |
|
|
| Server error (5xx) | "Something went wrong. Please try again." | [Retry] |
|
|
| Rate limit | "Too many attempts. Try again in {time}." | Timer countdown |
|
|
| Maintenance mode | "We're performing maintenance. Back soon!" | None |
|
|
|
|
### Position
|
|
- Field errors: 4px below field, left-aligned
|
|
- Form errors: Above form, full width, with icon
|
|
- System errors: Top of page, banner style, dismissible
|
|
```
|
|
|
|
---
|
|
|
|
## Timing and Animation
|
|
|
|
When timing matters, specify it precisely:
|
|
|
|
```markdown
|
|
## Modal Dialog Timing
|
|
|
|
### Opening Animation
|
|
- Duration: 200ms
|
|
- Easing: ease-out
|
|
- Sequence:
|
|
1. Backdrop fades in: 0% → 60% opacity
|
|
2. Modal scales + fades: scale(0.95) opacity(0) → scale(1) opacity(1)
|
|
3. Both complete simultaneously
|
|
|
|
### Closing Animation
|
|
- Duration: 150ms
|
|
- Easing: ease-in
|
|
- Sequence:
|
|
1. Modal fades out + scales down
|
|
2. When modal reaches 50% opacity: Backdrop starts fade out
|
|
3. Both complete, modal removed from DOM
|
|
|
|
### Auto-Dismiss (Success Message)
|
|
- Visible duration: 3 seconds
|
|
- Fade out: Last 300ms
|
|
- Total time on screen: 3.3s
|
|
- User can dismiss early by clicking X
|
|
|
|
### Delayed Appearance (Loading Spinner)
|
|
- Delay: 300ms
|
|
- Why: Don't flash spinner for quick operations
|
|
- If operation completes < 300ms: No spinner shown
|
|
- If operation > 300ms: Spinner appears
|
|
|
|
### Debounced Validation
|
|
- Delay: 1000ms after last keystroke
|
|
- Why: Don't validate while actively typing
|
|
- Triggers: After user stops typing for 1 second
|
|
- Example: Email availability check
|
|
```
|
|
|
|
---
|
|
|
|
## Accessibility Attributes in Detail
|
|
|
|
Complete ARIA specification for complex elements:
|
|
|
|
```markdown
|
|
## Dropdown Menu ARIA Specification
|
|
|
|
### Trigger Button
|
|
|
|
```html
|
|
<button
|
|
id="user-menu-button"
|
|
type="button"
|
|
aria-haspopup="true"
|
|
aria-expanded="false" <!-- Changes to "true" when open -->
|
|
aria-controls="user-menu-list"
|
|
aria-label="User menu">
|
|
[User Avatar] John Doe ▼
|
|
</button>
|
|
```
|
|
|
|
### Dropdown Container (when open)
|
|
|
|
```html
|
|
<ul
|
|
id="user-menu-list"
|
|
role="menu"
|
|
aria-labelledby="user-menu-button"
|
|
aria-orientation="vertical">
|
|
|
|
<li role="none">
|
|
<a role="menuitem" href="/profile">Profile</a>
|
|
</li>
|
|
|
|
<li role="none">
|
|
<a role="menuitem" href="/settings">Settings</a>
|
|
</li>
|
|
|
|
<li role="separator"></li>
|
|
|
|
<li role="none">
|
|
<button role="menuitem" type="button" onclick="logout()">
|
|
Log out
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
```
|
|
|
|
### Focus Management
|
|
1. When opened: Focus moves to first menu item
|
|
2. Arrow Down: Next menu item
|
|
3. Arrow Up: Previous menu item
|
|
4. Home: First menu item
|
|
5. End: Last menu item
|
|
6. Escape: Close menu, return focus to trigger
|
|
7. Tab: Close menu, move focus to next focusable element
|
|
8. Click outside: Close menu, focus stays where clicked
|
|
|
|
### Screen Reader Announcements
|
|
- Button: "User menu, button, collapsed"
|
|
- Opens: "User menu, menu, 4 items"
|
|
- Each item: "Profile, menu item" / "Settings, menu item" / etc.
|
|
- Closes: "User menu, button, collapsed"
|
|
```
|
|
|
|
---
|
|
|
|
## Translation Planning
|
|
|
|
Document content in all supported languages:
|
|
|
|
```markdown
|
|
## Task Status Badge Translations
|
|
|
|
### English
|
|
- pending: "Pending"
|
|
- in_progress: "In Progress"
|
|
- completed: "Completed"
|
|
- overdue: "Overdue"
|
|
|
|
### Spanish
|
|
- pending: "Pendiente"
|
|
- in_progress: "En Progreso"
|
|
- completed: "Completado"
|
|
- overdue: "Atrasado"
|
|
|
|
### German
|
|
- pending: "Ausstehend"
|
|
- in_progress: "In Bearbeitung"
|
|
- completed: "Abgeschlossen"
|
|
- overdue: "Überfällig"
|
|
|
|
### French
|
|
- pending: "En attente"
|
|
- in_progress: "En cours"
|
|
- completed: "Terminé"
|
|
- overdue: "En retard"
|
|
|
|
### Text Expansion Considerations
|
|
- English "Pending" (7 chars)
|
|
- German "Ausstehend" (10 chars) — 43% longer
|
|
- Design must accommodate ±40% expansion
|
|
- Badge width: Min 80px to handle longest translation
|
|
```
|
|
|
|
---
|
|
|
|
## Completeness Checklist
|
|
|
|
Use this to verify each element specification:
|
|
|
|
### For Every Element:
|
|
|
|
**States:**
|
|
- [ ] All possible states documented
|
|
- [ ] State transitions specified
|
|
- [ ] Default state clearly identified
|
|
- [ ] Edge case states covered
|
|
|
|
**Content:**
|
|
- [ ] Real text (not lorem ipsum)
|
|
- [ ] All labels written
|
|
- [ ] All error messages written
|
|
- [ ] All helper text written
|
|
- [ ] Translations provided (all supported languages)
|
|
|
|
**Accessibility:**
|
|
- [ ] ARIA role specified (if not semantic HTML)
|
|
- [ ] aria-label provided (where needed)
|
|
- [ ] aria-required for required fields
|
|
- [ ] aria-invalid for validation states
|
|
- [ ] aria-describedby for error messages
|
|
- [ ] Focus management specified
|
|
- [ ] Keyboard interactions documented
|
|
- [ ] Screen reader behavior described
|
|
|
|
**Behavior:**
|
|
- [ ] Click/tap behavior defined
|
|
- [ ] Keyboard behavior defined
|
|
- [ ] Validation timing specified
|
|
- [ ] Animation timing specified (if applicable)
|
|
- [ ] What triggers state changes
|
|
|
|
**Visual (if critical):**
|
|
- [ ] Colors specified (with hex codes)
|
|
- [ ] Sizes specified (touch targets 44px+)
|
|
- [ ] Spacing specified (if precise)
|
|
- [ ] Responsive behavior noted
|
|
|
|
---
|
|
|
|
## The Test
|
|
|
|
**Your element specification is complete when:**
|
|
|
|
✅ A developer can build it without asking questions
|
|
✅ A translator can extract all content
|
|
✅ A tester can verify every state
|
|
✅ An accessibility auditor can validate ARIA
|
|
✅ A designer can recreate it 6 months later
|
|
|
|
**If any role needs to guess, the spec is incomplete.**
|
|
|
|
---
|
|
|
|
## What's Next
|
|
|
|
In the tutorial, you'll practice writing complete specifications with Freya guiding you through each section. She'll ensure nothing is missed.
|
|
|
|
---
|
|
|
|
**[Continue to Tutorial: Write Your Specifications →](tutorial-11.md)**
|
|
|
|
---
|
|
|
|
[← Back to Lesson 2](lesson-02-section-widget-specifications.md) | [Back to Module Overview](module-11-conceptual-specifications-overview.md)
|
|
|
|
*Part of Module 11: Conceptual Specifications*
|