Compose Panel is a compact message-composition widget that composes TextArea, Button, and Badge into a form with To field, subject line, body, and send action. It provides a ready-to-use compose surface for SaaS messaging, email-like interfaces, and notification senders. The widget is intentionally minimal (size S) and does not include rich-text editing, attachments, or templates.
Goals
Deliver a <ComposePanel> component with To, Subject, and Body fields plus a Send button.
Compose existing TextArea, Button, and Badge primitives.
Validate required fields (To, Body) before enabling send.
Ship Storybook stories for the compose flow and validation states.
Non-Goals
Rich-text or WYSIWYG editing.
File or image attachments.
Address book / contact autocomplete.
Draft auto-save or persistence.
CC/BCC fields (deferred to future enhancement).
Scope
In Scope
Area
Description
Component
<ComposePanel> with To, Subject, Body fields and Send button
To Field
Text input for recipient; supports comma-separated entries displayed as badges
Subject Field
Single-line text input
Body Field
Multi-line TextArea for message body
Validation
Send button disabled until To and Body are non-empty
Storybook stories for compose flow, validation, and states
Out of Scope
Area
Reason
Rich-text editing
Adds complexity beyond S-size scope
File attachments
Separate feature
Contact autocomplete
Application-layer concern
CC/BCC
Future enhancement
Draft persistence
Application-layer concern
Users and Pain Points
User Groups
User
Description
Needs
Developers
Engineers building SaaS messaging or notification features
A composable compose form using DS primitives
Designers
Design-system consumers
Consistent compose UX aligned with DS tokens
End Users
SaaS application users
Simple, clear compose interface for sending messages
Pain Points
User
Pain Point
Impact
Developers
Building compose forms from scratch with recipient badges, validation, and send state
Repeated boilerplate across projects
End Users
Inconsistent compose UIs across SaaS apps
Learning curve, error-prone messaging
Definitions
Term
Definition
Compose Panel
A form widget for composing and sending a message
Recipient Badge
A styled tag showing a recipient’s address, removable by click
Send Payload
The structured data object passed to onSend: { to, subject, body }
Current State
Existing Behavior
The design system has TextArea, Button, and Badge as individual components. There is no compose-form widget that assembles them into a messaging composition surface.
Current Limitations
No compose-panel pattern exists.
Recipient badge rendering (comma-separated text to badge list) must be implemented from scratch.
Validation logic for compose forms is left to each consumer.
Existing Workarounds
Developers build compose forms ad hoc with raw input, textarea, and button elements.
Proposed Solution
Summary
Introduce <ComposePanel> that renders a compact form with a To field (text input that converts comma-separated entries into removable Badge components), a Subject text input, a Body TextArea, and a Send Button. The Send button is disabled until required fields are filled. On submit, onSend fires with a structured payload.
Key Capabilities
To field with comma/Enter-triggered badge creation and click-to-remove.
Subject field (optional but visible).
Body TextArea with auto-grow.
Send button with loading state during send.
Field validation with inline error messages.
Cancel/discard action.
User Experience
Users see a compact form. They type recipients in the To field; pressing comma or Enter converts the text to a badge. They fill in an optional subject and a message body, then click Send. If To or Body is empty, the Send button is disabled and inline errors appear on blur.
Developer Experience
<ComposePanel
onSend={({ to, subject, body })=>sendMessage({ to, subject, body })}
onCancel={()=>closePanel()}
/>
Requirements
ID
Requirement
Priority
Notes
FR-001
ComposePanel renders To, Subject, and Body fields with Send button
Must
-
FR-002
To field converts text to removable Badge components
Must
-
FR-003
Send button is disabled until To and Body are non-empty
Must
-
FR-004
onSend fires with structured { to, subject, body } payload
Must
-
FR-005
Send button shows loading state during async send
Should
-
FR-006
Cancel/discard action is available
Should
-
Priority Definitions
Priority
Meaning
Must
Required for this feature to ship.
Should
Important, but can be deferred if needed.
Could
Nice to have. Not required for initial release.
Functional Requirements
ID
Requirement
User Benefit
Priority
FUNC-001
To field input: typing text and pressing comma or Enter creates a Badge for that entry
Quick recipient entry
Must
FUNC-002
Clicking the remove icon on a recipient Badge removes it
Easy correction
Must
FUNC-003
Subject field is a single-line text input
Standard compose pattern
Must
FUNC-004
Body field is a TextArea with auto-grow up to a max height
Comfortable composition
Must
FUNC-005
Send button disabled when to.length === 0 or body.trim() === ""
Prevents incomplete sends
Must
FUNC-006
onSend receives { to: string[]; subject: string; body: string }
Typed, structured payload
Must
FUNC-007
isSending prop or internal state disables form and shows button loading indicator
Prevents double-send
Should
FUNC-008
onCancel fires when cancel/discard button is clicked
Panel dismissal
Should
FUNC-009
Inline validation errors show on To and Body fields on blur when empty
Clear error feedback
Must
Non-Functional Requirements
ID
Requirement
Category
Priority
NFR-001
Form renders in under 20ms
Performance
Must
NFR-002
All fields and buttons are keyboard-navigable in logical tab order