We’re on a mission to power and inspire real connections by making meeting easy and fun for every new generation of singles.
Careers at Tinder are big and bright
Create real connections
We’re doing something meaningful—helping people find their people. You’ll be proud of the experiences you help create for humans all over the world.
Forge our future
We’re a smaller team than you might think, which means everyone can have a big impact. Bring your entrepreneurial spirit, and you’ll have all the tools and support you need to make your presence felt.
Bring your light
We value unique perspectives and backgrounds. Our team is a caring (and fun!) bunch who appreciate differing opinions and like working and winning together.
Tinder Code
Take the Lead
We don't ghost our work or each other. Just as users don't leave their matches hanging, we don't let each other down.
Move Fast
We have a bias for action and urgency. Something that could be done tomorrow would be better if done today.
Better Together
We keep connection at the heart of dating and at the heart of how we work. Just as our users are better when they connect with others, so are we when we collaborate.
Real Talk
We say the hard thing the human way. Just as we ask our users to behave with kindness and candor in our community, we expect Team Tinder to do the same.
Safety First
We act with integrity, transparency, and consistency so people feel safe—whether they're swiping, matching, or working alongside us.
Spark Fun
We have fun to unlock creativity, fuel innovation, and help us build better experiences for daters.
How we fuelyour fire
Mind & body
Take care of yourself with benefits to keep you physically and mentally healthy.
Company perks
As winners of Comparably’s 2022 Best Company Perks and Benefits Award, we’re proud to say we provide perks that make a difference.
Life @ Tinder
We support each other— from informal check-ins to snacks + catered lunches at HQ to the flexibility to take time off when you need it.
Ignite your impact
Ready to make sparks fly in the lives of others—and in your own career?
Turns out, it’s not just our members finding their perfect match — our team has too. We’re proud to be recognized for creating one of the happiest, most supportive workplaces out there.
About our culture
We join for the mission and stay for the way we feel at work every day.
We look out for each other.
Connection isn’t just something we create for members—it starts with us. From day one you’ll have a buddy by your side and a team that always has your back.
We practice the lost art of listening.
Feedback is key to our culture. Whether it’s a suggestion from our members or our teammates, we want to hear it. The “contact us” button is always live.
Inclusion is hardwired here.
We’re the app that brought you the interracial dating emoji. Representation is core to our values, and we work hard to hire, develop, and promote talent from all backgrounds.
To serve a diverse, international member base, we need a diverse, international team. You’ll find opportunities to spark your career everywhere from Singapore to Switzerland to San Francisco.
The dating and relationships space is fascinatingly human (a.k.a. complex and challenging). It’s also ripe for innovation, and we’re going all in to lead the way.
We’re building something that sparks human connection, and that’s a fun world to work in. We never take ourselves too seriously, and we believe in a culture where hard work and joy aren’t mutually exclusive.
tag
Reads its config off the .verb-slot data attributes:
data-words comma-separated list
data-mode "slide" | "type"
data-width "fit" | "max"
data-dwell ms each word holds
============================================================== */
(function () {
var slot = document.querySelector('.verb-slot');
if (!slot) return;
var word = slot.querySelector('.verb');
if (!word) { console.warn('[hero] no .verb inside .verb-slot'); return; }
// The caret and the measurer are built here rather than in the
// Designer. They have to live inside the slot and inherit the
// headline's exact type, and hand-placing empty divs is the easiest
// thing in the world to get wrong. If you already made them in
// Webflow, these lines just adopt and reposition them.
function ensure(cls, tag) {
var el = slot.querySelector('.' + cls) || document.querySelector('.' + cls);
if (!el) { el = document.createElement(tag || 'span'); el.className = cls; }
if (el.parentElement !== slot) slot.appendChild(el);
return el;
}
var caret = ensure('verb-caret');
var measure = ensure('verb-measure');
// Belt and braces: the measurer must match the visible word's type
// exactly, or every width it reports is wrong and the slot crops.
function syncMeasureFont() {
var cs = getComputedStyle(word);
['fontFamily','fontSize','fontWeight','fontStyle','fontStretch',
'letterSpacing','textTransform','fontVariant'].forEach(function (p) {
measure.style[p] = cs[p];
});
measure.style.position = 'absolute';
measure.style.visibility = 'hidden';
measure.style.whiteSpace = 'nowrap';
measure.style.lineHeight = '1.08';
measure.style.top = '0';
measure.style.left = '0';
}
// Sizes the clipping box to the real glyph height. An inherited
// line-height (Webflow's body default is 1.5) inflates the line box
// well past the fixed height, and overflow:hidden then shows a
// sliver. Set inline so nothing in the cascade can override it.
// Measures the deepest descender across the actual word list, in px,
// rather than guessing a multiplier. The "g" in Design sits lower in
// a serif than in a sans, and lower again in some weights.
var _ctx;
function deepestDescender() {
try {
if (!_ctx) _ctx = document.createElement('canvas').getContext('2d');
var cs = getComputedStyle(word);
_ctx.font = cs.fontStyle + ' ' + cs.fontWeight + ' ' +
cs.fontSize + ' ' + cs.fontFamily;
var d = 0;
words.forEach(function (w) {
var m = _ctx.measureText(w);
if (m && typeof m.actualBoundingBoxDescent === 'number') {
d = Math.max(d, m.actualBoundingBoxDescent);
}
});
return d;
} catch (e) { return 0; }
}
function sizeSlot() {
var fs = parseFloat(getComputedStyle(word).fontSize) || 16;
word.style.lineHeight = '1.08';
syncMeasureFont();
measure.textContent = 'Hg'; // cap height + descender
var h = Math.ceil(measure.getBoundingClientRect().height) || Math.ceil(fs * 1.08);
measure.textContent = '';
// Generous is free here: the padding extends the clip box downward
// and the matching negative margin cancels it out of the layout,
// so extra room below costs nothing visually.
var d = deepestDescender();
var pad = Math.ceil(d > 0 ? d + 4 : fs * 0.32);
slot.style.boxSizing = 'content-box'; // see the CSS note
slot.style.height = h + 'px';
slot.style.paddingBottom = pad + 'px';
slot.style.marginBottom = -pad + 'px';
}
var words = (slot.dataset.words || word.textContent).split(',')
.map(function (w) { return w.trim(); })
.filter(Boolean);
// script is alive: hand the slot its fixed-width, clipped behaviour
slot.classList.add('is-ready');
if (!slot.dataset.words) {
console.warn('[hero] no data-words attribute found — rotating a single word only');
}
var dwell = parseInt(slot.dataset.dwell, 10) || 1900;
var i = 0;
var timer = null;
var widths = [];
var maxW = 0;
var reduce = window.matchMedia('(prefers-reduced-motion: reduce)');
var headline = slot.closest('.hero-headline');
var tail = headline ? headline.querySelector('.hero-tail') : null;
var MAX_FS = 104; // px, desktop ceiling
var MIN_FS = 20; // px, never go below this
if (!headline) console.warn('[hero] no .hero-headline ancestor — auto-sizing off');
if (headline && !tail) console.warn('[hero] no .hero-tail found — auto-sizing off');
function measureWords() {
syncMeasureFont();
widths = words.map(function (w) {
measure.textContent = w;
return measure.getBoundingClientRect().width;
});
measure.textContent = '';
maxW = Math.max.apply(null, widths);
// sanity check: the widest word can never be narrower than the
// word currently on screen. If it is, the measurer is not
// inheriting the headline's type and every width is garbage.
var live = word.getBoundingClientRect().width;
if (live && maxW < live * 0.9) {
console.warn('[hero] measured widths look too small (' +
Math.round(maxW) + 'px vs ' + Math.round(live) +
'px on screen) — check that .verb-measure sits inside .verb-slot');
maxW = Math.max(maxW, live);
widths = widths.map(function (w) { return Math.max(w, live); });
}
}
// Sizes the headline so the WIDEST verb still fits on one line.
// Sized off the widest word, not the current one, so the line
// never reflows mid-rotation.
function measureAll() {
// rotation must still work even if the auto-sizing can't run
if (!headline || !tail) { measureWords(); sizeSlot(); applyWidth(i, 0); return; }
var host = headline.parentElement || document.body;
var avail = host.clientWidth - 4;
if (!avail) { measureWords(); sizeSlot(); applyWidth(i, 0); return; }
headline.style.setProperty('--hero-fs', MAX_FS + 'px');
measureWords();
var gap = parseFloat(getComputedStyle(headline).columnGap) || 0;
var lineW = maxW + gap + tail.getBoundingClientRect().width;
var fs = lineW > avail
? Math.max(MIN_FS, Math.floor(MAX_FS * (avail / lineW)))
: MAX_FS;
headline.style.setProperty('--hero-fs', fs + 'px');
measureWords();
sizeSlot();
applyWidth(i, 0);
}
function applyWidth(index, dur) {
var target = slot.dataset.width === 'max' ? maxW : widths[index];
slot.style.setProperty('--slot-dur', (dur || 0) + 'ms');
slot.style.setProperty('--slot-w', Math.ceil(target) + 'px');
}
/* ---------- slide ---------- */
function slideTo(next) {
var dur = 300;
applyWidth(next, 420);
word.animate(
[{ transform: 'translateY(0)', opacity: 1 },
{ transform: 'translateY(-0.9em)', opacity: 0 }],
{ duration: dur, easing: 'cubic-bezier(.6,0,.35,1)', fill: 'forwards' }
).onfinish = function () {
word.textContent = words[next];
word.animate(
[{ transform: 'translateY(0.9em)', opacity: 0 },
{ transform: 'translateY(0)', opacity: 1 }],
{ duration: 340, easing: 'cubic-bezier(.2,.7,.3,1)', fill: 'forwards' }
);
};
}
/* ---------- type ---------- */
function typeTo(next) {
var from = words[i], to = words[next], n = from.length;
if (slot.dataset.width === 'fit') {
// width follows the characters, so the line breathes as it types
slot.style.setProperty('--slot-dur', '0ms');
}
function setText(t) {
word.textContent = t;
if (slot.dataset.width === 'fit') {
measure.textContent = t;
var w = measure.getBoundingClientRect().width;
measure.textContent = '';
slot.style.setProperty('--slot-w', Math.ceil(w) + 'px');
caret.style.setProperty('--caret-x', Math.ceil(w) + 2 + 'px');
} else {
measure.textContent = t;
caret.style.setProperty('--caret-x',
Math.ceil(measure.getBoundingClientRect().width) + 2 + 'px');
measure.textContent = '';
}
}
(function erase() {
if (n > 0) { setText(from.slice(0, --n)); return void setTimeout(erase, 42); }
var m = 0;
(function write() {
if (m < to.length) { setText(to.slice(0, ++m)); return void setTimeout(write, 68); }
if (slot.dataset.width === 'fit') slot.style.setProperty('--slot-dur', '420ms');
queue();
})();
})();
}
function step() {
var next = (i + 1) % words.length;
if (reduce.matches) {
word.textContent = words[next];
applyWidth(next, 0);
i = next; queue(); return;
}
if (slot.dataset.mode === 'type') { typeTo(next); i = next; return; }
slideTo(next); i = next; queue();
}
function queue() {
clearTimeout(timer);
timer = setTimeout(step, reduce.matches ? dwell + 1200 : dwell);
}
function reset() {
clearTimeout(timer);
i = 0;
word.textContent = words[0];
word.getAnimations().forEach(function (a) { a.cancel(); });
word.style.transform = '';
word.style.opacity = 1;
measureAll();
if (slot.dataset.mode === 'type') {
measure.textContent = words[0];
caret.style.setProperty('--caret-x',
Math.ceil(measure.getBoundingClientRect().width) + 2 + 'px');
measure.textContent = '';
}
queue();
}
// custom webfonts change every width, so wait for them
if (document.fonts && document.fonts.ready) document.fonts.ready.then(measureAll);
measureAll();
queue();
window.addEventListener('resize', measureAll);
reduce.addEventListener('change', reset);
// pause when the tab is hidden
document.addEventListener('visibilitychange', function () {
if (document.hidden) clearTimeout(timer); else queue();
});
})();