Skip to content

Narrow the remaining Chat components to curated props #439

Description

@czarandy

Follow-up to #438, which replaced ChatScrollButton's ComponentPropsWithoutRef<'div'> extension with a curated ButtonPassthroughProps set. The rest of the Chat directory still has the wide-open pattern:

  • ChatLayout.tsx:38ComponentPropsWithoutRef<'div'>
  • ChatComposer.tsx:35Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'onChange' | 'onSubmit'>
  • ChatComposerInput.tsx:24Omit<ComponentPropsWithoutRef<'textarea'>, 'onChange' | 'value'>
  • ChatMessage.tsx:20ComponentPropsWithoutRef<'article'>
  • ChatMessageList.tsx:22ComponentPropsWithoutRef<'div'>
  • ChatMessageBubble.tsx:18ComponentPropsWithoutRef<'div'>
  • ChatMessageMetadata.tsx:30ComponentPropsWithoutRef<'div'>
  • ChatSystemMessage.tsx:14ComponentPropsWithoutRef<'div'>

Each spreads ...rest onto its root element, so the entire DOM prop surface is accepted and forwarded — including props that fight the component's own contract (role, aria-live, data-sender, data-chat-message) with no indication which wins.

Narrow each to the props a consumer might reasonably need, matching the approach in #438.

Two cases need more than a mechanical swap:

  • ChatMessage computes aria-label/aria-labelledby from name/sender and spreads ...rest before them, so a consumer label is silently dropped today. The curated version should let the consumer's value win and fall back to the generated one.
  • ChatMessageList hardcodes aria-live="polite". A static transcript that should not be announced has no way to opt out.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions