React with C++: Building the Quip Mac and Windows Apps



  • Fast — Data should be stored locally and synced passively. Loading a document shouldn’t require a network roundtrip and should be as fast as opening as file on your hard drive.
  • Offline Support — The app should work offline or online. No primary operation (editing, sending messages, sharing) should require a network connection.
  • Share Code — The app should share as much code with the desktop web site as possible. We don’t want to maintain three different versions of the app across Windows, Mac, and Web.

Data API

message SendMessageHandler {
message Request {
optional string text = 1;
optional int64 sent_usec = 2;
repeated File file_attachments = 3;
message Response {
optional Message sent_message = 1;
bool Handlers::SendMessage(
const SendMessageHandler::Request& request,
SendMessageHandler::Response* response) {
Message* message = response->mutable_sent_message();
// ...
string serialized;
return level_db_->Put(message->id(), serialized).OK()
def send_message_handler(request):
response = SendMessageHandler.Response()
# ...

Data Model


message Document {
optional string id = 1;
optional string title = 2;
optional string created_by_id = 3;
// ...
message Message {
optional string id = 1;
optional string author_id = 2;
optional string text = 3;
// ...
var MessageBubble = React.createClass({
mixins: [ModelObjectListener],
propTypes: {
message: React.PropTypes.instanceOf(Message).isRequired
render: function() {
return <div class="message-bubble">
modelObjectsForProps: function(props) {
return [props.message];


message Index {
optional string index_id = 1;
message Entry {
optional string object_id = 1;
optional string sort_value = 2;
repeated Entry entries = 2;
var MessageList = React.createClass({
mixins: [ModelIndexListener],
propTypes: {
messageIndex: React.PropTypes.instanceOf(Index).isRequired
render: function() {
return <div class="message-list">
{this.props.messageList.forEach(function(messageId) {
return <MessageBubble message={Message.get(messageId)}/>
modelIndexesForProps: function(props) {
return [props.messageIndex];


message Changes {
repeated Object changed_objects = 1;
repeated Index changed_indexes = 2;



  • An HTML version of the CRAY-1 Hardware Reference Manual was imported into Microsoft Word 2011 (Version 14.5.2) and cleaned up slightly
  • The resulting content was repeated 10 times, to better simulate the original document (the HTML version was only of the first 3 chapters)
  • The resulting file (see CRAY-1-HRM x10.docx attachment) was imported into Quip as CRAY-1 Computer System®.
  • The document is 599 pages long and approximately 3.4MB in size (PDF).
  • The document was opened with the respective desktop apps (Word, Quip) already running (but without them having previously loaded the document in the session)
  • Loading times were measured by recording the screen with ScreenFlow and counting the frames (at 30 fps) between the user gesture to open the document and the contents appearing (without pictures being fully loaded).
  • Documents were opened from the in-app document browsing UI in Quip and Google Docs, and from the “Open…” panel in Microsoft Word
  • Recordings were done 5 times for each application and the results were averaged.
  • Tests were conducted on a MacBook Pro (Retina, 15-inch, Mid 2012 2.7 GHz Core i7, 16 GB of RAM) running Mac OS X 10.9.5. Chrome 43.0.2357.132 with a new profile was used for Quip Web and Google Docs.


Technical Links




Ex-CTO of Facebook, co-founder/CEO of FriendFeed and co-creator of Google Maps.

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Bret Taylor

Bret Taylor

Ex-CTO of Facebook, co-founder/CEO of FriendFeed and co-creator of Google Maps.

More from Medium

Deploy NodeJS APP on Elastic Beanstalk Using CodePipeline(CI/CD)

Getting started with MongoDB with node.js

Run GUI app in Docker