Qaid
ARTICLE

Position & Placement: Where to Put Your Feedback Buttons

Put the feedback buttons in a corner, inline with your content, or in a container you control, without colliding with everything else that is fixed.

Qaid Team

Every site already has something in the bottom-right corner. Working out where the feedback buttons go is mostly working out what is already there and what happens when they overlap.

Where they land by default

Bottom-right of the viewport, 16 pixels in from both edges. That corner is where the web has put its floating buttons for fifteen years, so nobody has to be taught what they are.

<script
  src="https://unpkg.com/@qaiddev/thumbs-embed/dist/embed.js"
  data-endpoint="/api/feedback"
></script>

It is also, for the same reason, the corner most likely to be occupied already.

The four corners

position takes one of four values:

  • bottom-right (default)
  • bottom-left
  • top-right
  • top-left
<script
  src="https://unpkg.com/@qaiddev/thumbs-embed/dist/embed.js"
  data-endpoint="/api/feedback"
  data-position="bottom-left"
></script>

Or in JavaScript:

import { QaidFeedback } from '@qaiddev/thumbs-embed';

new QaidFeedback({
  endpoint: '/api/feedback',
  position: 'top-right'
});

Picking one

Bottom-right unless you have a reason. It is what people expect and it stays clear of your content.

Bottom-left when a chat or help launcher already owns the other side. This is the common case.

Top-right on documentation sites and prototypes, where feedback is closer to a primary action. Check it against your header first, because that is usually where the header lives.

Top-left is the one you reach for when the other three are taken, or on a right-to-left layout where it reads as bottom-right does here.

Nudging it off the edge

offset moves the buttons in from whichever two edges they are pinned to:

new QaidFeedback({
  endpoint: '/api/feedback',
  position: 'bottom-right',
  offset: { x: 24, y: 24 }
});

Or via data attributes:

<script
  src="https://unpkg.com/@qaiddev/thumbs-embed/dist/embed.js"
  data-endpoint="/api/feedback"
  data-offset-x="24"
  data-offset-y="24"
></script>

Push it out on an airy layout, pull it in when you need the pixels.

Mounting it in the page instead

A floating button asks for feedback about the whole site. A button at the end of an article asks about the article. The container option takes a CSS selector and mounts the embed inside whatever it finds:

Mounted in a container

Feedback buttons mounted inside a custom container

Loading embed...
<div id="feedback-container"></div>

<script
  src="https://unpkg.com/@qaiddev/thumbs-embed/dist/embed.js"
  data-endpoint="/api/feedback"
  data-container="#feedback-container"
></script>

Inside a container the buttons position relative to it rather than to the viewport, and position stops doing anything at all.

Three places this pays off

End of an article. You are asking somebody who has just finished reading, about the thing they just read.

<article>
  <h1>How to Configure Your Server</h1>
  <p>...</p>

  <div class="feedback-section">
    <p>Was this article helpful?</p>
    <div id="article-feedback"></div>
  </div>
</article>

<script>
import { QaidFeedback } from '@qaiddev/thumbs-embed';

new QaidFeedback({
  endpoint: '/api/feedback',
  container: '#article-feedback',
  skipTargeting: true
});
</script>

A feature card. One embed per card tells you which feature the vote was about.

A sidebar. Always reachable, and it costs you no corner.

Stacking order

The embed sits at z-index: 50. That is low on purpose: it loses to your modals and wins against your page. When it lands on the wrong side of something, move it:

new QaidFeedback({
  endpoint: '/api/feedback',
  zIndex: 9999
});
<script
  src="https://unpkg.com/@qaiddev/thumbs-embed/dist/embed.js"
  data-endpoint="/api/feedback"
  data-z-index="9999"
></script>

What you are competing with

Dialogs usually sit at 1000 or above and should keep winning. Cookie banners run to 9999 and so do most chat launchers, which is why moving corners beats raising the number. Navigation dropdowns land between 100 and 500 and rarely overlap the corners anyway.

If a dialog is open, the dialog wins. Raising the embed above one is how you end up with a thumbs-up button floating over a payment form.

Different placement on small screens

The buttons scale down on their own and stay reachable. Placement is the part that sometimes needs a hand.

With a media query

Inside a container, CSS does all of it:

#feedback-container {
  position: fixed;
  bottom: 16px;
  right: 16px;
}

@media (max-width: 768px) {
  #feedback-container {
    bottom: 80px; /* Above mobile navigation */
    right: 8px;
  }
}

By branching at init

When the difference is more than layout, pick the config before constructing:

import { QaidFeedback } from '@qaiddev/thumbs-embed';

const isMobile = window.matchMedia('(max-width: 768px)').matches;

new QaidFeedback({
  endpoint: '/api/feedback',
  position: isMobile ? 'top-right' : 'bottom-right',
  offset: isMobile ? { x: 8, y: 8 } : { x: 16, y: 16 },
  buttonSize: isMobile ? 'small' : 'medium'
});

Sharing the corners

Chat launchers, cookie banners, scroll-to-top buttons and toast notifications all want the same few hundred pixels. Four ways out, cheapest first.

Look at what is already there

Scroll to the bottom of your own site and count. Bottom-right will have your chat launcher and your scroll-to-top button. Bottom-left is usually free. Top-right holds notification bells and user menus, though those normally live in the header rather than floating. Top-left is almost always empty.

Move to an empty corner

The fix that costs nothing. Chat on the right, feedback on the left.

Stack them

If both have to be in the same corner, raise the offset until they clear each other:

// Assuming a chat widget takes up the first 60px from the bottom
new QaidFeedback({
  endpoint: '/api/feedback',
  position: 'bottom-right',
  offset: { x: 16, y: 80 } // Clear the chat widget
});

Position a container yourself

When you need the buttons at an exact spot, put a fixed element there and mount into it:

.fixed-actions {
  position: fixed;
  bottom: 16px;
  right: 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: flex-end;
}
<div class="fixed-actions">
  <div id="feedback-buttons"></div>
  <button class="scroll-to-top">Top</button>
</div>

Hide them until hovered

Incognito mode keeps the corner empty until a pointer arrives:

new QaidFeedback({
  endpoint: '/api/feedback',
  incognito: true
});

Nothing to collide with when nothing is drawn. The cost is that a reader who never hovers there never learns the buttons exist.

The four options in one place

OptionValuesDefaultNotes
positionbottom-right, bottom-left, top-right, top-leftbottom-rightIgnored when container is set
offset{ x: number, y: number }{ x: 16, y: 16 }Pixels from edge
containerCSS selectorundefinedMounts inline instead of fixed
zIndexnumber50Adjust for layering conflicts

Leave the defaults alone until something collides. Most sites never need to touch any of this.

Back to all articles