{"id":16396,"date":"2023-12-05T18:52:41","date_gmt":"2023-12-05T18:52:41","guid":{"rendered":"https:\/\/slack.engineering\/?p=16396"},"modified":"2023-12-05T18:52:41","modified_gmt":"2023-12-05T18:52:41","slug":"building-custom-animations-in-the-workflow-builder","status":"publish","type":"post","link":"https:\/\/slack.engineering\/building-custom-animations-in-the-workflow-builder\/","title":{"rendered":"Building Custom Animations in the Workflow Builder"},"content":{"rendered":"<p>Slack users have more power than ever to automate routine tasks and processes, saving themselves time each day. Workflow Builder, a task automation tool built into Slack, has continued to improve since its launch back in 2019. Along with various new steps and triggers, we built a new sidebar section for all available workflow steps. These steps are now accessible to users without having to open a modal.<\/p>\n<figure id=\"attachment_16402\" aria-describedby=\"caption-attachment-16402\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-16402 size-full\" src=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc1.png\" alt=\"\" width=\"1600\" height=\"988\" srcset=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc1.png 1600w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc1.png?resize=640,395 640w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc1.png?resize=768,474 768w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc1.png?resize=1280,790 1280w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc1.png?resize=1536,948 1536w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc1.png?resize=380,235 380w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc1.png?resize=800,494 800w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc1.png?resize=1160,716 1160w\" sizes=\"auto, (max-width: 1600px) 100vw, 1600px\" \/><figcaption id=\"caption-attachment-16402\" class=\"wp-caption-text\">Before<\/figcaption><\/figure>\n<figure id=\"attachment_16403\" aria-describedby=\"caption-attachment-16403\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-16403 size-full\" src=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc2.png\" alt=\"\" width=\"1600\" height=\"718\" srcset=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc2.png 1600w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc2.png?resize=640,287 640w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc2.png?resize=768,345 768w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc2.png?resize=1280,574 1280w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc2.png?resize=1536,689 1536w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc2.png?resize=380,171 380w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc2.png?resize=800,359 800w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc2.png?resize=1160,521 1160w\" sizes=\"auto, (max-width: 1600px) 100vw, 1600px\" \/><figcaption id=\"caption-attachment-16403\" class=\"wp-caption-text\">After<\/figcaption><\/figure>\n<p>The enhancement of the Slack Platform, coupled with smart and significant design changes, makes Workflow Builder a new and powerful experience for users automating tasks in Slack.<\/p>\n<p>Powerful tools can be intimidating, though. On the Workflow Builder team, we identified animations as a great opportunity to create friendly and approachable UI magic.\u00a0 Simple actions, like moving or adding steps, should have a Slack touch \u2014 the smooth and fun interaction patterns that Slack is known for.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-16404 size-full\" src=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc3.gif\" alt=\"\" width=\"1000\" height=\"663\" \/><\/p>\n<p>The Workflow Builder experience already had drag-and-drop animations when moving steps within a workflow. But, with the newly introduced sidebar, a drag-and-drop inconsistency was exposed. <b>Why can\u2019t users drag and drop a step from the sidebar into the workflow?<\/b><\/p>\n<h2><b>Working with an animation library<\/b><\/h2>\n<p>Unfortunately, drag-and-drop animations from our new steps sidebar into a workflow were not simple to support.<\/p>\n<p>Workflow Builder uses<a href=\"https:\/\/github.com\/atlassian\/react-beautiful-dnd\/tree\/master\"> react-beautiful-dnd<\/a> \u2014 a library that supports drag-and-drop interactions with natural animations. Even though this library is powerful, it is also opinionated and has limitations.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium\" src=\"https:\/\/user-images.githubusercontent.com\/2182637\/53607406-c8f3a780-3c12-11e9-979c-7f3b5bd1bfbd.gif\" width=\"500\" height=\"456\" \/><\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-16411 size-full\" src=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc4-1.png\" alt=\"\" \/><\/p>\n<p>The react-beautiful-dnd library works by wrapping components in a React context. It supports drag-and-drop animations by encasing a list of draggable components in a droppable area. That\u2019s fun to say, right?<\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/atlassian\/react-beautiful-dnd\/blob\/master\/docs\/api\/drag-drop-context.md\">&lt;DragDropContext \/&gt;<\/a> &#8211; Wraps the drag-and-drop part of your application<\/li>\n<li><a href=\"https:\/\/github.com\/atlassian\/react-beautiful-dnd\/blob\/master\/docs\/api\/droppable.md\">&lt;Droppable \/&gt;<\/a> &#8211; Wraps areas where items can be dropped, and contains<code> &lt;Draggable \/&gt;<\/code> s<\/li>\n<li><a href=\"https:\/\/github.com\/atlassian\/react-beautiful-dnd\/blob\/master\/docs\/api\/draggable.md\">&lt;Draggable \/&gt;<\/a> &#8211; Wraps items that can be dragged around<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>This worked well for dragging and dropping steps within a workflow \u2014 we had a singular list of steps and these steps could be moved within the droppable context.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-16422 size-full\" src=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc5-1.png\" alt=\"\" width=\"960\" height=\"589\" srcset=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc5-1.png 960w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc5-1.png?resize=640,393 640w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc5-1.png?resize=768,471 768w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc5-1.png?resize=380,233 380w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc5-1.png?resize=800,491 800w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-16420 size-full\" src=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc6.png\" alt=\"\" width=\"960\" height=\"566\" srcset=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc6.png 960w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc6.png?resize=640,377 640w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc6.png?resize=768,453 768w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc6.png?resize=380,224 380w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc6.png?resize=800,472 800w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><\/p>\n<p>But we needed to rethink that strategy to support drag-and-drop animations for the steps sidebar. Instead of wrapping a portion of the builder, we needed to wrap the entire builder page with the drag-and-drop context, and have two separate lists of draggables and droppables. This would allow for steps to be moved from one list to the other.<\/p>\n<h2><b>Animation value is in the details <\/b><\/h2>\n<p>Building on the existing drag-and-drop support within Workflow Builder, we were able to get drag-and-drop between the steps sidebar and the workflow steps list working. However, \u201cit works\u201d has never been our quality bar for production experiences.\u00a0 We realized animations should also create a pleasant and encouraging experience. With that in mind, before a public release of the features, we went to the next phase of prototyping \u2014 polish.<\/p>\n<p>We learned the value of animations as we found solutions to complicated issues:<\/p>\n<ul>\n<li>Using context providers and responders\n<ul>\n<li>Fitting drag-and-drop support easily in our codebase<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<ul>\n<li>Working with legacy Workflow Builder components\n<ul>\n<li>Leveraging legacy components for the new Workflow Builder<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<ul>\n<li>Creating custom animations\n<ul>\n<li>Animating the drop of a step into a workflow<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<ul>\n<li>Making dynamic placeholders\n<ul>\n<li>Adding a placeholder when dragging a step over a droppable area<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<ul>\n<li>Solving hint box spacing problems\n<ul>\n<li><span style=\"color: var(--content-text__color);font-family: var(--content-text__FontFamily);font-size: var(--content-text__FontSize)\">Ensuring the animations worked smoothly with existing hint boxes<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<ul>\n<li>Experimenting with a tilt animation\n<ul>\n<li>Creating fun tilt animations as you drag a step<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3>Using context providers and responders<\/h3>\n<p>The react-beautiful-dnd library works by using<a href=\"https:\/\/github.com\/atlassian\/react-beautiful-dnd\/blob\/master\/docs\/guides\/responders.md\"> responders<\/a>. These are \u201ctop-level application events that you can use to perform your own state updates, style updates, as well as to make screen reader announcements.\u201d The library required us to maintain the state of drag-and-drop information and to have a centralized place for state-specific actions.<\/p>\n<p>Our custom context provider wrapper was a great solution for this. We stored information about the step being dragged, the destination information, and the location of where the step was being dragged over. Actions \u2014 such as what happens when you drop or add a step \u2014 were also maintained here. This information was updated dynamically by the provided react-beautiful-dnd responders and maintained in an isolated Workflow Builder drag-and-drop component wrapper.<\/p>\n<pre><code class=\"language-javascript\">&lt;WorkflowDragDropContext.Provider value={workflowContexts}&gt;\n\t\t\t   &lt;DragDropContext\n\t\t\t\t   onBeforeCapture={onBeforeCapture}\n\t\t\t\t   onBeforeDragStart={onBeforeDragStart}\n\t\t\t\t   onDragUpdate={onDragUpdate}\n\t\t\t\t   onDragEnd={onDragEnd}\n\t\t\t   &gt;\n\t\t\t\t   {children}\n\t\t\t   &lt;\/DragDropContext&gt;\n &lt;\/WorkflowDragDropContext.Provider&gt;<\/code><code class=\"language-javascript\">\n<\/code><\/pre>\n<h3>Working with legacy Workflow Builder components<\/h3>\n<p>The new Workflow Builder frontend is supported by the legacy Workflow Builder components. This was an engineering decision made when we first started building out the new experience. By reusing existing components, we were able to develop quickly, and get things like validation, the step interface, and the trigger interface out of the box. However, supporting legacy workflows while adding features to new workflows was a challenge.<\/p>\n<p>We solved this by dynamically moving the drag-and-drop context. By checking the type of workflow, and if the feature was turned on or not, we could allow both the old and new drag-and-drop support to coexist. Having a thought-out plan for using our powerful Workflow Builder components, and testing thoroughly, was key to the development of new features.<\/p>\n<h3>Creating custom animations<\/h3>\n<p>Workflow Builder steps in the sidebar are a different size than the steps in the list. This caused a very awkward default drag-and-drop animation.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-16483 size-full\" src=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/ezgif.com-crop-2-7.gif\" alt=\"\" width=\"852\" height=\"467\" \/><\/p>\n<p>We created helper functions that modified the original react-beautiful-dnd styling. We used the destination width to translate the position of the dragged step to the middle of the workflow step list.<\/p>\n<pre><code class=\"language-javascript\">const translate = `translate(${moveTo.x + destinationWidth - stepItemWidthHalf}px, ${moveTo.y}px)`<\/code><\/pre>\n<p>&nbsp;<\/p>\n<p>The destination width was calculated by the library responders \u2014 using<a href=\"https:\/\/github.com\/atlassian\/react-beautiful-dnd\/blob\/master\/docs\/guides\/responders.md#phase-1-capture\"> onBeforeDragStart<\/a> in particular. We queried the DOM before dragging occurred and located the droppable destination container to find the width. Our custom drag-and-drop context wrapper worked perfectly to hold this information and was used to update the style.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-16480 size-full\" src=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/ezgif.com-crop-2-4.gif\" alt=\"\" width=\"821\" height=\"442\" \/><\/p>\n<h3>Making dynamic placeholders<\/h3>\n<p>After a few iterations, we noticed it was very difficult to understand where a step could be dropped. This posed a huge challenge since react-beautiful-dnd did not support adding placeholders.\u00a0 We needed to be creative to achieve the dragging effect we wanted. Drawing some<a href=\"https:\/\/codesandbox.io\/s\/react-beautiful-dnd-custom-placeholder-2lmf1\"> inspiration<\/a>, we created a custom segment to dynamically render a placeholder based on where the user was dragging a step.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-16476 size-full\" src=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/ezgif.com-crop-2.gif\" alt=\"\" width=\"996\" height=\"510\" \/><\/p>\n<p>As drag was being updated, we located the destination DOM element, the dragged DOM element, and the width and height of the placeholder. To find the x-coordinate and y-coordinate, we used the destination index and calculated the position in the DOM. This placeholder size was passed into the drag-and-drop context provider in the workflow step list.<\/p>\n<pre><code class=\"language-javascript\">{{      (isDraggingOver || (isDraggingOverLastDroppable &amp;&amp;\n\t   !isSourceWorkflowList)) &amp;&amp; (\n\t\t\t  &lt;div\n\t\t\t\t  style={{\n\t\t\t\t  top:\n\t\t\t\t  placeholderElementSizing.clientY +\n\t\t\t\t  HALF_DIVIDER_HEIGHT,\n\t\t\t\t  left: placeholderElementSizing.clientX,\n\t\t\t\t  height: placeholderElementSizing.clientHeight,\n\t\t\t\t  width: placeholderElementSizing.clientWidth,\n\t\t\t\t  }}\n\t\t\t\t  \/&gt;\n\t\t\t\t\t  )}\n<\/code><\/pre>\n<h3>Solving hint box spacing problems<\/h3>\n<p>Workflow Builder has many moving parts and one of those is hint boxes. When a user clicks in between steps, a hint box appears and prompts the user to add a step. This is helpful but it was causing issues with drag-and-drop. Showing the placeholder while dragging caused spacing issues because it is technically not a step. Additionally, it did not make sense to see the placeholder while the user was trying to move the step to a different position.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1600\" height=\"798\" class=\"alignnone size-medium wp-image-16445\" src=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc8.png?w=640\" alt=\"\" srcset=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc8.png 1600w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc8.png?resize=640,319 640w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc8.png?resize=768,383 768w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc8.png?resize=1280,638 1280w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc8.png?resize=1536,766 1536w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc8.png?resize=380,190 380w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc8.png?resize=800,399 800w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/doc8.png?resize=1160,579 1160w\" sizes=\"auto, (max-width: 1600px) 100vw, 1600px\" \/><\/p>\n<p>The clear solution was to remove the hint box while dragging. This required an in-depth knowledge of the difference between state updates with <code>onBeforeDragStart<\/code> vs <code>onBeforeCapture<\/code> responders. We initially tried to reset the placeholders with the <code>onBeforeDragStart<\/code> responder.<\/p>\n<pre><code class=\"language-javascript\"> \u00a0const OnBeforeDragStart = useCallback(\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0() =&gt; {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ Before dragging starts reset the \n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ hint box to avoid awkward spacing\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0setHideHintBox(true);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0},\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0[dispatch]\n\u00a0\u00a0\u00a0);<\/code><\/pre>\n<p>We quickly realized this would not work. The state was not updated in time. React-beautiful-dnd DOM detected the placeholder&#8217;s existence even though it was not there, causing noticeable spacing problems.<\/p>\n<p>We replaced the <code>onBeforeDragStart<\/code> responder with <code>onBeforeCapture<\/code>. The difference between these responders is that <code>onBeforeCapture<\/code> supports modifying the DOM before any calculation occurs. Hiding and resetting the hint box before the dragging action allowed us to create a better user experience and solve our problem.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-16481 size-full\" src=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/ezgif.com-crop-2-5.gif\" alt=\"\" width=\"912\" height=\"459\" \/><\/p>\n<h3>Experimenting with a tilt animation<\/h3>\n<p>Animations can always be enhanced. Adding a tilt was a design decision that was initially a prototype. Our designer, Kyle Tezak, had a fun idea to add a tilt to the step when dragging. Working closely with an engineer and the Design Technology team, we created a proof-of-concept prototype. This was demoed to the team and everyone loved the idea \u2014 why not make a repetitive action exciting? We knew we had to share this with our customers.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-16479 size-full\" src=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/ezgif.com-crop-2-3.gif\" alt=\"\" width=\"907\" height=\"456\" \/><\/p>\n<p>We created a Natural Drag component that took a style object and modified the rotation based on how fast the user was dragging. We added this animation by using the<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/window\/requestAnimationFrame\"> requestAnimationFrame<\/a> window method and created a smooth tilt effect that lasted as long as the user was dragging the step.<\/p>\n<pre><code class=\"language-javascript\">const newStyle =\n\t\t   snapshot.isDragging &amp;&amp; !snapshot.dropAnimation\n\t\t\t   ? {\n\t\t\t\t\t   ...style,\n\t\t\t\t\t   transform: modifiedAnimation.transform,\n\t\t\t\t }\n\t\t\t   : style;\n<\/code><\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-16477 size-full\" src=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/ezgif.com-crop-2-1.gif\" alt=\"\" width=\"922\" height=\"479\" \/><\/p>\n<h2><b>What animation taught our team<\/b><\/h2>\n<p>Animation in the Workflow Builder became our opportunity to spotlight powerful, new features. Over countless iterations, we fine-tuned the drag-and-drop UI to be a pleasant and productive experience for power users and new users. We learned a lot of engineering lessons along the way \u2014 especially around finding creative ways to work within a complicated codebase. These challenges paved the way for new design and engineering animation capabilities in the builder.<\/p>\n<p>&nbsp;<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-16495 size-full\" src=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/12\/Screenshot-2023-12-01-at-8.01.34\u202fAM.png\" alt=\"\" width=\"780\" height=\"207\" srcset=\"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/12\/Screenshot-2023-12-01-at-8.01.34\u202fAM.png 780w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/12\/Screenshot-2023-12-01-at-8.01.34\u202fAM.png?resize=640,170 640w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/12\/Screenshot-2023-12-01-at-8.01.34\u202fAM.png?resize=768,204 768w, https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/12\/Screenshot-2023-12-01-at-8.01.34\u202fAM.png?resize=380,101 380w\" sizes=\"auto, (max-width: 780px) 100vw, 780px\" \/><\/p>\n<p>At Slack, craft is central to every aspect of our design and engineering life cycle. It\u2019s the small things, like making adding steps feel fun and smooth, that give you the confidence to explore new features and want to use them again. Dedication to craft and investing in small, delightful interactions all add up to make work simpler, more pleasant, and more productive for our users.<\/p>\n\t\t<div class=\"hiring\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"26\" height=\"37\" fill=\"none\" viewbox=\"0 0 26 37\"><path stroke=\"#032d60\" stroke-linejoin=\"round\" stroke-width=\"5\" d=\"m4.112 1c-2.5 6.167-2.4 21.1 18 31.5\"\/><path stroke=\"#032d60\" stroke-width=\"5\" d=\"m20.112 18 2.5 14.5-13.5 1.5\"\/><\/svg>\n\t\t\t<p>We&#039;re hiring; come work with us!<\/p>\n\t\t\t<a href=\"https:\/\/slack.com\/careers\"\n\t\t\t\tclass=\"\" target=\"_blank\"\n\t\t\t\tdata-clog-click=\"\"\n\t\t\t\tdata-clog-trigger=\"trigger=\"\n\t\t\t\tdata-clog-ui-element=\"\"\n\t\t\t\tdata-clog-ui-component=\"\">Apply now<\/a>\n\t\t<\/div>\n\t\n","protected":false},"excerpt":{"rendered":"Slack users have more power than ever to automate routine tasks and processes, saving themselves time each day. Workflow Builder, a task automation tool built into Slack, has continued to improve since its launch back in 2019. Along with various new steps and triggers, we built a new sidebar section for all available workflow steps.&hellip;","protected":false},"author":388,"featured_media":16464,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[3],"tags":[511,528,563,564],"class_list":{"0":"post-16396","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-uncategorized","8":"tag-automation","9":"tag-css","10":"tag-front-end-development","11":"tag-frontend","12":"ts-entry"},"acf":{"subtitle":"","author_group":{"configure_author":"wordpress","authors":[{"ID":16399,"post_author":"388","post_date":"2023-11-30 20:48:32","post_date_gmt":"2023-11-30 20:48:32","post_content":"","post_title":"Christina Mudarth","post_excerpt":"","post_status":"publish","comment_status":"closed","ping_status":"closed","post_password":"","post_name":"christina-mudarth","to_ping":"","pinged":"","post_modified":"2023-12-01 16:15:18","post_modified_gmt":"2023-12-01 16:15:18","post_content_filtered":"","post_parent":0,"guid":"https:\/\/slack.engineering\/?post_type=author&#038;p=16399","menu_order":0,"post_type":"author","post_mime_type":"","comment_count":"0","filter":"raw"}],"custom_author":""},"series":false,"tags":[511,528,563,564]},"jetpack_featured_media_url":"https:\/\/slack.engineering\/wp-content\/uploads\/sites\/7\/2023\/11\/WorkflowBuilderRL-Robot@2x.png","_links":{"self":[{"href":"https:\/\/slack.engineering\/wp-json\/wp\/v2\/posts\/16396","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/slack.engineering\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/slack.engineering\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/slack.engineering\/wp-json\/wp\/v2\/users\/388"}],"replies":[{"embeddable":true,"href":"https:\/\/slack.engineering\/wp-json\/wp\/v2\/comments?post=16396"}],"version-history":[{"count":52,"href":"https:\/\/slack.engineering\/wp-json\/wp\/v2\/posts\/16396\/revisions"}],"predecessor-version":[{"id":16503,"href":"https:\/\/slack.engineering\/wp-json\/wp\/v2\/posts\/16396\/revisions\/16503"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/slack.engineering\/wp-json\/wp\/v2\/media\/16464"}],"wp:attachment":[{"href":"https:\/\/slack.engineering\/wp-json\/wp\/v2\/media?parent=16396"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/slack.engineering\/wp-json\/wp\/v2\/categories?post=16396"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/slack.engineering\/wp-json\/wp\/v2\/tags?post=16396"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}