Design Tools and AI-Assisted Workflows Questions
Working efficiently and confidently inside a design tool such as Figma, Sketch, or Adobe XD. Covers organizing files, pages, and layers for a team; naming conventions that stay searchable as a project grows; version history, branching, and merge practices that let several designers work at once without overwriting each other; and diagnosing a shared file that has grown slow to open and edit. Covers building components in the tool so they hold up in practice, using its layout, resizing, and variant systems so a component adapts across screen sizes and survives real content instead of tidy placeholders. Also covers working faster and automating repetition: keyboard shortcuts, choosing workflow plugins and knowing when to avoid them, and occasionally scripting one; export settings for production assets, including formats, scale factors, and file naming; and choosing or migrating between design tools for a team's needs. Does not cover design token architecture, component governance, or design system versioning; prototype fidelity or interaction pattern choices; accessibility auditing; responsive and multi-platform design strategy; or handoff specs, redlines, and developer communication, each of which is its own topic.
Outline a practical naming convention for Figma layers, frames, and components that scales across multiple teams. Provide examples (e.g., button/primary/large, input/text/disabled) and explain how your convention improves searchability, component discoverability, and developer handoff.
Sample Answer
Direct answer
Use a hierarchical, slash-delimited convention of component, then property, then value, rather than free-text names, because a design tool like Figma turns forward slashes in a name into folder-like groups in its asset browser, and for a proper component with defined variant properties, exposes those same segments as filterable dropdowns rather than as separate, unrelated names.
Structured elaboration
Core pattern: name from general to specific, component/property/value, e.g. button/primary/large, input/text/disabled. This mirrors how someone actually searches: they usually know the component ("button") before they know the exact variant they need.
Casing and separators: pick one style, lower-case with hyphens for multi-word segments, e.g. icon-button/social/facebook, and enforce it everywhere, so a search for "button" reliably surfaces every button-family layer regardless of who created it.
Variant properties, not just names: for a real component with combinable variants, define each axis as its own variant property (State: Default, Hover, Disabled; Size: Small, Large) rather than encoding every combination into one long string. Mechanically, that means building each combination first as its own separate component (a Default/Small button, a Default/Large button, a Hover/Small button, and so on), selecting all of them at once, and running Figma's "Combine as variants" action (from the right-click menu, or the button that appears in the toolbar once multiple components are selected). That merges the separate components into a single component set, and Figma auto-detects the differing part of each one's name to make a first pass at the property axes; from there you open the component set's properties panel and rename each auto-generated property ("Property 1", "Property 2") to something meaningful ("State", "Size") and clean up its list of values. This is what actually produces a searchable, filterable dropdown in the panel; a flat text name is just a label, it doesn't give you that behavior on its own.
Frames and layers get named by role, not by shape. A frame represents a screen or section and should be named the way a user would describe that screen ("Checkout / Payment step"), not by position ("Frame 12"). Groups and layers inside get named by what they are ("Icon - chevron down"), not by their default shape name ("Vector 4").
Scaling across teams: publish the naming rules in the design-system documentation rather than leaving them as tacit convention, and enforce lightly, for example a spot-check by the design-system owner before a new component is published, since informal conventions drift once more than one team contributes to the same library.
Worked example
A design-system team publishes a Button component with variant properties Type (Primary, Secondary, Ghost), Size (Small, Large), and State (Default, Disabled). In the insert panel this shows up as one searchable "Button" entry with three dropdown filters, instead of the twelve separately-named components those three axes actually multiply out to (3 types x 2 sizes x 2 states = 12 combinations), things like "button-primary-small" and "button-primary-large-disabled" sitting side by side with no relationship to each other. That multiplication is the point: every axis you add multiplies the flat-naming cost while leaving the variant-set cost flat at one entry with one more dropdown, which is why the gap widens exactly as a library grows. A form team building a signup screen searches "input," finds input/text/disabled and input/text/error as clean, predictable siblings. A second team, months later, building an unrelated settings screen and never having talked to the first team, guesses the same search term and lands on the same family; that's the discoverability payoff in practice. On developer handoff, an instance named Button > Primary > Large shows up in the tool's inspection view with that same readable path, letting the engineer identify exactly which design-system component and variant to reference in code, instead of guessing from a name like "Rectangle 219."
Trade-offs and pitfalls
Nesting more than two or three meaningful segments becomes as unreadable as having no convention at all, so resist the urge to encode everything into the name. A convention nobody enforces decays quickly once a project is under deadline pressure, which is why periodic file audits matter, not just the initial documentation. Naming without actually restructuring into real variant properties is a half-measure: giving a component a flat name like button/primary/large without ever defining Type and Size as variant properties still won't produce the filterable dropdown behavior, so treat the naming convention as inseparable from actually adopting the tool's variant feature, not as a cosmetic label layered on top of separately built components.
You're responsible for making sure an entire component library, not just one component, behaves well across mobile, tablet, and desktop. What's your strategy, and how do you represent those decisions in the design tool itself so engineering can implement predictable, consistent behavior without guessing?
Sample Answer
Direct answer
I'd treat responsive behavior as a system-level policy, a small, shared set of breakpoints, sizing rules, and spacing tokens that every component inherits, defined once, rather than a decision each designer re-makes per component. Then I'd encode that policy directly into each component's own Auto Layout and constraint setup (constraints are the rules on a layer that say how it resizes or repositions when its parent frame resizes) and document it on the component itself, so engineering reads the same predictable rule off of any instance instead of reverse-engineering intent component by component.
Strategy
- Define the shared vocabulary first, independent of any single component: agree on breakpoints (the widths where layout logic changes), a fixed spacing/sizing token scale rather than arbitrary per-component pixel choices, and a small named set of resizing behaviors, for example "Fluid" (fills and reflows with its container), "Hug" (sized by its own content, so it grows and shrinks with its label or children), "Fixed" (constant size regardless of both container and content), and "Stepped" (a different one of the above at each defined breakpoint). Hug earns its place in the vocabulary rather than being folded into Fixed, because "does not stretch to fill its container" and "is a constant size" are genuinely different behaviors, and collapsing them is what produces buttons specced at a hardcoded width.
- Represent it per component, consistently: every component that should be Fluid is built with fill-container sizing and a documented min/max width; every Stepped component gets explicit breakpoint variants using the same breakpoint values used everywhere else in the library, never locally invented ones.
- Document the rule on the component, not in a separate file: use the component's description field (or an annotation frame right next to it in the library) to state its resizing behavior, its min/max constraints, and which breakpoint variants exist, so an engineer opening the component sees the rule attached to the thing itself instead of cross-referencing a spec that can drift out of date.
- Govern the shared vocabulary: assign an owner or small review group for it. A component that seems to need a resizing behavior the vocabulary doesn't have yet is a signal to extend the system deliberately, not to improvise locally, since ad hoc one-off resizing logic is exactly what makes engineering guess.
- Validate with a kitchen-sink page: a single page in the library file with every component dropped into representative mobile, tablet, and desktop frames side by side, so a library-wide review can confirm consistency in one place instead of checking every component's own page individually.
Worked example
Shared vocabulary: breakpoints at 375 (mobile), 810 (tablet), 1440 (desktop) px; a spacing scale of 4/8/12/16/24/32/48; four resizing behaviors, Fluid, Hug, Fixed, Stepped. Applied to the library: a Button component is Stepped: Hug at tablet and desktop, so its width comes from its own label rather than from whatever container it lands in, and Fluid at mobile, where a primary call to action conventionally spans the full content column. Calling Button "Fixed" is the tempting shortcut and it is wrong twice over, since a button that hugs its label is not a constant size and a mobile primary CTA does stretch; the flagship component is exactly where a vocabulary missing Hug does its most damage, because every consuming team copies whatever the button did. A Card component is Fluid horizontally, fill-container with a documented min-width of 280 and max-width of 400, using the 16 spacing token for internal padding. A Navigation component is Stepped, with real breakpoint variants at each of the three widths, because its structure genuinely changes shape (a hamburger menu on mobile, a condensed tab set on tablet, a full tab bar on desktop) rather than just resizing. The Card's description field states plainly: "Fluid, min 280 / max 400, padding token spacing/16, no dedicated breakpoint variants needed since fill plus min/max fully describes its behavior," so an engineer implementing it knows to use the equivalent of min/max width plus flex-grow without guessing from three static frames.
flowchart TD
A["Shared resizing vocabulary: breakpoints, spacing scale, Fluid or Hug or Fixed or Stepped"] --> B["Build component with Auto Layout mapped to vocabulary"]
B --> C["Document the rule on the component itself"]
C --> D["Kitchen sink page: all components at mobile, tablet, desktop"]
D --> E{"Consistent?"}
E -- "No" --> B
E -- "Yes" --> F["Ship to consuming files"]
Trade-offs and pitfalls
- The upfront cost is real, defining a shared vocabulary and retrofitting existing components to it is slower than letting each designer solve responsiveness locally per component, but local solutions are exactly what produces the inconsistency this problem is about; the investment pays off starting at the second and third component, not the first.
- Forcing every component into exactly four resizing behaviors can produce an awkward fit for a genuinely unusual one; the governance step exists so a real exception gets added to the system deliberately, instead of being forced into the wrong bucket or handled as an ungoverned one-off.
- A description embedded in the component only stays accurate if updating the resizing behavior and updating its description are treated as one atomic edit, part of the same review checklist, not two separate habits.
- This only works if the library has real authority, teams actually consuming it instead of duplicating components locally; the responsive policy is only as strong as the governance enforcing it.
Explain how you would use Figma's version history, branching, and restore features to manage multiple design explorations and avoid file conflicts for a feature that requires A/B experiments and multiple designers iterating simultaneously. Provide a step-by-step example workflow including branch naming and merge practices.
Sample Answer
Direct answer
I'd use Branching (a feature that spins off a separate, linked copy of a file so you can work in isolation until you deliberately merge changes back into the main file) to give each experiment variant its own protected space to iterate in, keep the main file as the single agreed source of truth, and use Version History (Figma's automatically saved timeline of a file's past states, which you can name and restore from) as the safety net and audit trail inside each branch rather than as the collaboration mechanism itself.
Step-by-step workflow
- Branch per variant, not per person, unless two designers exploring the same variant risk stepping on each other's messy in-progress state. Figma's own real-time multiplayer canvas already lets multiple people co-edit one file live without conflict, so branching is for isolating explorations that shouldn't interfere with each other, not for basic simultaneous editing.
- Name branches predictably:
{feature}/{variant}-{short-desc}, e.g.checkout-ab/variant-a-single-columnandcheckout-ab/variant-b-progressive-disclosure. Tag the branch or a page inside it with the same experiment ID used in the analytics/experimentation platform, so a PM can map "Variant B" straight back to the exact Figma branch. - Snapshot inside the branch: save named checkpoints to Version History at meaningful moments ("v1, initial layout," "v2, after PM feedback") so exploration attempts inside that one branch can be compared or rolled back without leaving it. If a branch's history needs to jump back to an earlier explored state, use Restore on that named version rather than manually rebuilding it.
- Review before merge: request a review on the branch; Figma shows what changed relative to main, and a reviewer comments directly on it, the same way a pull request gets reviewed in code.
- Merge the winner: once the experiment read-out or design review picks a direction, merge that branch into main. Figma flags a conflict if main changed underneath the branch in the meantime (for example, a shared component both variants used got updated independently).
- Close out: keep the losing variant's branch around read-only for the record rather than merging it, and immediately save a clearly named version on main ("post checkout A/B merge, variant B shipped") so anyone auditing later can jump straight to the agreed state instead of scrolling raw history.
Worked example
Two designers, Ana and Marcus, are exploring a checkout redesign for an A/B test. Main file: "Checkout Flow, source of truth." Ana branches checkout-ab/variant-a-single-column, Marcus branches checkout-ab/variant-b-progressive. Each saves two or three named versions as they iterate. After a week, the design review likes variant B's layout but variant A's button styling. Because Figma merges a whole branch at once rather than reconciling individual layers the way git merges lines, the fix isn't a partial merge; Ana updates the button styling directly inside Marcus's branch using the shared component library, and only that single combined branch gets merged into main.
Trade-offs and pitfalls
- Branching solves file-conflict isolation, not design disagreement; the human call over which parts of which exploration win still has to happen before the merge, since Figma can't automatically reconcile two branches' edits to the same layer tree the way git reconciles non-overlapping code lines.
- Version History inside a branch is only useful if someone actually saves named checkpoints; left to pure auto-save, it becomes a wall of untitled snapshots that's hard to navigate mid-experiment.
- A common shortcut, duplicating pages inside one file per variant instead of branching, avoids the merge step but pollutes the single source-of-truth file with dead-end explorations, and makes it easy for a shared component update to silently reach a variant nobody's using anymore.
Your company has a legacy Sketch library with inconsistent styles and many detached components. Outline a migration plan to Figma that preserves design intent, extracts tokens, consolidates components, and minimizes disruption to active product work. Include recommended steps, plugins or tools you'd use, QA checks, and rollback contingencies.
Sample Answer
Direct answer
I'd treat this as an incremental, verifiable migration rather than a big-bang cutover: import and audit the legacy library first, extract its true design intent into a canonical token set before rebuilding anything, migrate one product area at a time behind a QA gate, and keep the original Sketch file frozen untouched throughout as both the reference and the rollback point.
Migration plan
- Audit: import the Sketch library into Figma using Figma's native Sketch-file importer, but as a working copy, never the destination file, so the "before" state stays comparable at every step. Inventory which styles are actually applied versus orphaned, and find every detached component (a copy that's lost its link back to its original master symbol), since each one is either an intentional variant or unreconciled drift that needs a human decision.
- Extract tokens: before rebuilding anything, pull the actual color, type, and spacing values in use into a canonical token set (a design token is just a named, reusable value like "color/primary" or "spacing/16" used instead of a hardcoded hex code or pixel number scattered across layers). An inconsistent legacy library reliably surfaces near-duplicate values (three blues one or two shades apart); each one needs a call: consolidate to one, or keep as a genuinely distinct token.
- Consolidate components: rebuild each canonical component fresh using Auto Layout (Figma's layout system where a frame automatically resizes, spaces, and aligns its child layers as content changes, instead of every element being positioned and sized by hand) and Figma's variant system, rather than porting each Sketch symbol one-to-one, since a straight port just carries the original inconsistency into the new format. This is also the moment to resolve the detached-component drift found in the audit.
- Minimize disruption: migrate by product area, starting with the smallest, most self-contained one to validate the approach before scaling it. Active product work keeps using the old library until its specific area's migration is validated, so nobody's mid-sprint file breaks under them. The legacy Sketch file and the untouched imported copy stay frozen the entire time.
- QA checks: visually diff each migrated component against its legacy counterpart at real usage sizes to catch subtle drift (padding off by a couple of pixels, a substituted font weight); confirm every consuming file that pointed at the old component now correctly resolves to the new one, with nothing left pointing at an orphaned reference; spot-check that already-shipped product still matches, since a silent one-pixel token change can create a visible gap against what's already live.
- Rollback: because the legacy file is never edited or deleted during the process, rollback is simply pointing consuming files back at the old library, not reconstructing anything. Treating each migrated product area as its own reversible unit, rather than merging the whole migration as one step, means a bad call in one area doesn't force reverting everything.
Worked example
The legacy library has five near-identical blues where one primary color was intended, three card components (one canonical, two detached and modified by different feature teams), and gaps hardcoded as 8, 10, 12, and 16px where a single 8-based spacing scale was intended. After import and audit: blue #1E5FBF is used 340 times, #1E60C0 just 12 times (clearly copy-paste rounding drift), and three other blues under 5 times each (likely intentional secondary colors). Decision: consolidate the two near-identical blues into one color/primary token, keep the genuinely distinct ones as their own tokens. For the card: the canonical version becomes the new Auto Layout component; one detached copy turns out to be an intentional "compact" variant (kept as a real component variant), the other is unintentional drift, a padding value nudged and forgotten, reconciled back to the standard. For spacing, only one of the four values is genuine drift. 8 and 16 already sit on the intended 8-based scale and simply become spacing/8 and spacing/16. The stray 10 is a hand-nudged near-miss of 8 with no consistent context behind it, so it folds into spacing/8. 12 is also off the 8-based scale, but it turns out to be applied consistently in one specific context, so it survives as a deliberate spacing/12 rather than being rounded away. Four hardcoded numbers therefore resolve to three tokens, not one: the audit's job is to separate drift from intent, and an audit that forces every off-scale value onto the scale destroys real decisions along with the accidents, which is a harder mistake to detect afterwards than leaving one extra token in place.
Trade-offs and pitfalls
- A straight one-to-one import-and-rename is fast but ships the original inconsistency forward in a new format; the real value is in the audit and consolidation judgment, which takes longer and can't be fully delegated to a bulk tool pass.
- Migrating everything at once looks efficient on a timeline but removes rollback granularity and blocks active product work while it's validated; area-by-area is slower on paper but is the only version where a bad call doesn't stall the whole team.
- Community plugins can help automate parts of this, bulk style auditing, duplicate detection, spec-diffing, and are worth evaluating for whatever's actually available and reliable at the time of the migration, but the plan shouldn't depend on any specific one existing or behaving a particular way. If nothing suitable is available, the audit still has to happen by hand.
- No tool substitutes for the judgment calls above, deciding which drift is intentional and which component becomes canonical; tooling is an efficiency aid on top of that judgment, not a replacement for it.
You're designing a component that has to survive real content: variable-length text, user-uploaded images of unpredictable size, and a live data feed that might return nothing or far too much. Walk through how you'd build and stress-test it in Figma so it holds up across breakpoints and platforms instead of breaking the moment the content isn't the tidy placeholder you designed with.
Sample Answer
Direct answer
I'd build the component using Auto Layout (Figma's system for making a frame automatically resize, space, and align its children as content changes, instead of every layer being sized and placed by hand) so its size is driven by whatever content actually fills it, rather than a fixed frame sized to look right with the one tidy example I designed with, then deliberately stress-test it against a spread of realistic and adversarial content, empty, minimal, typical, and maximal, instead of only the happy path, so the breakage shows up in the design file rather than in production.
Building for variability
- Sizing: give every layer the right Auto Layout sizing mode for what it is: "hug" for text that should grow or shrink with its content, "fill" for anything that should stretch to its container, "fixed" only where a size is genuinely constant. The component's overall height or width becomes a function of its actual content, not an assumption baked into the frame.
- Text: decide a max-line or truncation rule up front (e.g. a 2-line clamp with an ellipsis) instead of leaving text unconstrained, and deliberately decide what a very short title (one word) should look like too, not just what a very long one does.
- Images: use a fixed-aspect-ratio container with a defined fill/crop behavior, so user-uploaded images of arbitrary source dimensions don't distort the layout or leave visible gaps. Decide and document what "no image at all" looks like as its own state (the layout reclaims that space, or shows a placeholder), rather than treating it as a smaller version of "has an image."
- Live data feed: design three states beyond the happy path explicitly: empty (real empty-state guidance, not a blank frame), sparse (one or two items, where a grid can otherwise look broken or lonely), and overflow (far more items than fit, needing pagination, infinite scroll, or a "show more" affordance you actually design rather than assume the tool or engineering will handle).
Stress-testing method
Don't validate only against your own placeholder copy. Pull or fabricate a genuinely adversarial content set, the longest real title you can find, a small or oddly-cropped real user-uploaded image, an empty feed and an overloaded one, and drop it into the component across every breakpoint and platform frame, checking specifically for text overlap, image distortion, broken row alignment between sibling cards, and inconsistent row heights in a grid. Re-run the same content set per platform, not just per breakpoint width, since comfortable line length and touch-target sizing differ by platform convention even at similar widths.
Worked example
Take a feed card. Content test set: a 1-character title through a genuinely long real headline (~120 characters); images including a square avatar, a wide banner photo, and a "no image" case; feed sizes of zero items, one item, exactly enough to fill one row, and far more than fit. Result of the stress test: the long headline without a clamp pushes that card's height noticeably past its row neighbors, breaking alignment, fixed by adding a 2-line clamp. The wide banner photo inside a container built for square avatars either stretches or leaves visible letterboxing, fixed by standardizing the image container's aspect ratio and fill behavior regardless of the source image's shape. The "no image" case leaves a blank gray box the same size as a populated one, reading as a broken loading state rather than an intentional one, fixed with a component property that removes the image slot and lets the text stack take that space, used only for the genuine "no image" case (a separate, distinct treatment covers "image still loading"). A one-item feed on a grid built for three columns leaves two glaring empty cells, fixed by having the grid collapse to a left-aligned row of only the populated cards instead of reserving ghost slots.
Trade-offs and pitfalls
- Designing purely for the absolute worst case (every field maxed out) makes the typical, common case look padded and awkward; the goal is testing the full range, then choosing defaults, like a 2-line clamp, that degrade gracefully rather than breaking at the extreme or looking wrong in the common case.
- Treating "no image" as just a smaller version of "has an image" instead of its own layout state is the most common source of a card that reads as subtly broken rather than intentionally different.
- Empty and overflow feed states are often left undesigned because they feel like edge cases, but the choice between pagination, infinite scroll, and a "show more" button is a real UX decision. Leaving it undesigned just hands that decision to whoever implements it, with no design intent behind it.
- Stress-testing with genuinely messy content matters because generic filler text is uniform in a way that hides exactly the length-variance problems the test exists to catch.
Unlock Full Question Bank
Get access to all 19 Design Tools and AI-Assisted Workflows interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.