Component Organization
Components are organized by domain insrc/app/components/:
UI Library: Folds
Sable uses Folds (v2.6.1), a custom React component library providing:- Buttons, inputs, and form controls
- Layout primitives (Box, Flex, Grid)
- Overlays (modals, popovers, tooltips)
- Navigation components
- Typography and icons
Importing Folds Components
Folds Configuration
Folds styles are initialized in the app entry point:Styling with Vanilla Extract
Sable uses Vanilla Extract for type-safe, scoped CSS-in-TypeScript.Creating Styles
Using Styles in Components
Color System
Colors are defined insrc/colors.css.ts using Vanilla Extract’s theming:
React Patterns
Component Composition
Sable favors composition over inheritance:Hooks-Based Logic
Components use hooks for stateful logic (see 100+ hooks insrc/app/hooks/):
Render Props
For flexible rendering:Virtualization
Large lists use TanStack Virtual:Key Component Categories
Editor Components
The rich text editor (src/app/components/editor/) is built with Slate.js:
Main Files:
Editor.tsx- Main editor componentElements.tsx- Custom element renderers (blocks, inlines)Toolbar.tsx- Formatting toolbarinput.ts- Input normalizationoutput.ts- Serialize to Matrix eventskeyboard.ts- Keyboard shortcuts
autocomplete/):
EmoticonAutocomplete.tsx- Emoji suggestionsUserMentionAutocomplete.tsx- @mention completionRoomMentionAutocomplete.tsx- #room completionAutocompleteMenu.tsx- Menu UI
Emoji Board
The emoji picker (src/app/components/emoji-board/):
Structure:
EmojiBoard.tsx- Main componentcomponents/- SubcomponentsLayout.tsx- Grid layoutGroup.tsx- Emoji groupsItem.tsx- Individual emojiSidebar.tsx- Category navigationSearchInput.tsx- Search barTabs.tsx- Emoji/Sticker tabs
- Virtualized grid for performance
- Search with emoji shortcodes
- Recent emoji tracking
- Custom emoji and sticker packs
- Skin tone selection
Message Components
Message rendering (src/app/components/message/):
Attachment Types (attachment/):
- Image, video, audio attachments
- File downloads
- Blurhash placeholders
- Encrypted media decryption
content/):
- HTML message bodies
- Markdown rendering
- Code blocks with syntax highlighting
- Link previews
- Reply threads
layout/):
- Modern layout (default)
- Compact layout (IRC-style)
- Bubble layout (chat bubbles)
Media Components
Audio/video playback (src/app/components/media/):
- Progressive loading
- Custom controls
- Authenticated requests (via service worker)
- Thumbnail generation
- image-viewer/ - Lightbox with zoom and pan gestures
- pdf-viewer/ - PDF.js integration with pagination
- image-editor/ - Basic image cropping/editing
Navigation Components
Navigation UI (src/app/components/nav/, sidebar/):
- Room/space hierarchy
- Unread indicators
- Drag-and-drop reordering (Pragmatic Drag & Drop)
- Collapsible categories
- Search and filters
Animation
Sable uses Framer Motion for animations:Gesture Handling
Mobile gestures use@use-gesture/react:
Accessibility
Components usereact-aria for accessibility:
Testing Patterns
While test files are not included in the source, components are designed for testability:- Pure functional components
- Logic extracted to hooks
- Dependency injection via props
- Controlled vs. uncontrolled variants
Best Practices
- Use Folds components before building custom UI
- Colocate styles with components using Vanilla Extract
- Extract complex logic to custom hooks
- Leverage TypeScript for prop validation
- Memoize expensive computations with
useMemo - Virtualize long lists with TanStack Virtual
- Handle loading states explicitly
- Provide accessibility attributes (ARIA labels, roles)
- Test in mobile viewport - Sable is mobile-first
- Follow the existing patterns - consistency matters