Download - Swapping Out Text, Five Different Ways
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 1/21
It's a common need in web apps: you click something and the text of the thing you just clicked changes. Perhaps
something simple like a "Show" button that swaps to "Hide", or "Expand Description" to "Collapse Description." This is
a fairly simple thing to do, but there are various considerations to make. Let's cover a bunch of ways.
jQuery Way (Less Markup / More JavaScript)
You need to store the "swap" text somewhere. I'd say in most cases it is a design/view concern so storing it in the
markup is a good idea. We'll use the example of a button who's text swaps between "Hide" and "Show". A data-*
attribute is a perfectly good place to store the swap text. So that becomes:
It's easy to swap out the text, like:
But, if we did that we'd lose the orignal text forever. We need to store the original text first. Another data-* attribute will
do.
To do that on a click event, you'd do:
<button data-text-swap="Show">Hide</button>
HTML
var button = $("button");
button.text(button.data("text-swap"));
jQuery
var button = $("button");
button.data("text-original", button.text());
button.text(button.data("text-swap"));
jQuery
var button = $("button");
button.on("click", function() {
button.data("text-original", button.text());
jQuery
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 2/21
But that only goes one direction. To complete the "swap", we'll need to compare the current text value of the button to
see if it matches the swap text or not. If it does, change it back to the original. If not, to the swap text. This is what it
looks like all done:
jQuery Way (More Markup / Less JavaScript)
If we're willing to set that value in the original markup, we can simplify the JavaScript a bit.
We can use a single ternary operator to check if the swap matches the orignal and perform the right action based on
the truthiness.
Vanilla JavaScript Way
I'm guilty of using too much jQuery around here for things that can be done without it. This is what the first "less
markup" version would look like in "raw" JavaScript:
button.text(button.data("text-swap"));
});
$("button").on("click", function() {
var el = $(this);
if (el.text() == el.data("text-swap")) {
el.text(el.data("text-original"));
} else {
el.data("text-original", el.text());
el.text(el.data("text-swap"));
}
});
jQuery
data-text-original
$("button").on("click", function() {
var el = $(this);
el.text() == el.data("text-swap")
? el.text(el.data("text-original"))
: el.text(el.data("text-swap"));
});
jQuery
var button = document.querySelectorAll("button")[0];
button.addEventListener('click', function() {
if (button.getAttribute("data-text-swap") == button.innerHTML) {
button.innerHTML = button.getAttribute("data-text-original");
} else {
JavaScript
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 3/21
CSS Way (with jQuery changing class names)
Since this is a view concern and could be considered a "state," a popular idea is to use JavaScript only to change
classes which represent states and let CSS define what the visual change actually is.
We could use the class "on" to represent the swap state. Then that class would apply a pseudo element covering the old
word and replacing it with the swap word. I don't think actual button elements with default browser styling take well to
pseudo element so let's use an anchor here.
This is a bit funky, to be fair. I think this is almost worse that putting the swap word in the JavaScript. CSS isn't really
meant for this kind of thing and likely has some accessibility concerns.
This also happens to work because the word "Hide" is smaller than "Show" a little bit. If the swap word was bigger, the
original would stick out underneath the white cover. You might be able to get around that by inline-blocking the
original, hiding the overflow, and kicking the original out of the box with text-indent. But the fact that the replacement
word is absolutely positioned removes it from the flow, which could be an issue, not to mention real world design isn't
always a simple as flat-color-on-flat-color.
CSS-Only Way
But hey as long as we're getting funky, we could use The Checkbox Hack here to make the text swap entirely CSS. The
replacement happens the exact same way, it just happens when an invisible checkbox right before the word is either
or not. This means the word needs to be in a label as well, which is able to toggle that checkbox's state
through the for attribute.
button.setAttribute("data-text-original", button.innerHTML);
button.innerHTML = button.getAttribute("data-text-swap");
}
}, false);
a {
position: relative;
}
a.on:after {
content: "Hide";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: white;
}
CSS
:checked
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 4/21
Demo of All Five Ways
<input id="example-checkbox" type="checkbox">
<label for="example" id="example">Show</label>
HTML
#example {
position: relative;
}
#example-checkbox {
display: none;
}
#example-checkbox:checked + #example:after {
content: "Hide";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: white;
}
CSS
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 5/21
More?
How have you done this kind of thing in the past? We didn't cover just putting the swap word right in the JavaScript...
how do you feel about that?
SHARE ON
Twitter Facebook Google+
Related Posts
Add (+/-) Button Number Incrementers
CSS :target for Off-Screen Designs
So You Need To Fill a Dropdown Dynamically
HTML CSS JS Result Edit on
Text Swapping
jQuery Way (more markup / less js)
Hide
jQuery Way (less markup / more js)
Hide
Vanilla JS Way
Hide
CSS Way w/ jQuery class change
CSS Only Way
Show
Show
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 6/21
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 7/21
Comments
Matt Litherland# J UL Y 2 , 2 0 1 3
Nice article Chris, i’m using this right now on a CodePen :-)
Subash# J UL Y 2 , 2 0 1 3
What about using in css to get data from html instead of hard coding that.
–
attr()
<input id="example-checkbox" type="checkbox">
<label for="example" id="example" data-text="Hide">Show</label>
#example {
position: relative;
}
#example-checkbox {
display: none;
}
#example-checkbox:checked + #example:after {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: white;
}
Rhys L# J UL Y 2 4 , 2 0 1 3
Not bad Subash, not bad.
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 8/21
Litek# J UL Y 2 , 2 0 1 3
Whenever I swap things – even single word – I use js only to switch classes:
and css:
More markup, less js but feels better:)
<span class="btn show-default">
<span "text-default">show</span>
<span "text-altered">hide</span>
</span>
.show-default > .text-altered { display:none; }
.show-altered > .text-default { display:none; }
Chris Coyier# J UL Y 2 , 2 0 1 3
Yah with I guess it’s not even an accessibility concern really eh?display: none;
Jeff Carlsen# J UL Y 2 , 2 0 1 3
This is how I prefer to do it (usually wrapped in an anchor instead of a span). This way a keyboard user
can select it, and the screen reader will always read what it currently says. Change the class, and the
screen reader now reads the new text when returning to the link.
Andy F# J UL Y 2 , 2 0 1 3
The data-* attributes on elements can also be accessed via element.dataset, so you could also write your
‘raw’ JavaScript example like this:
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 9/21
Of course, that won’t work in IE < 11, but we can dream :(
var button = document.querySelectorAll("button")[0];
button.addEventListener('click', function() {
if (button.dataset.textSwap === button.textContent) {
button.textContent = button.dataset.textOriginal;
} else {
button.dataset.textOriginal = button.textContent;
button.textContent = button.dataset.textSwap;
}
}, false);
Peter Foti# J UL Y 2 , 2 0 1 3
Rather than storing both the original text and the text to swap in their own data attributes and using if/else
logic to choose which one to show, you could just use a single data attribute to store whichever text is not
currently being shown, and then just swap the values. Less markup required.
$("button").on("click", function() {
var el = $(this),
tmp = el.text();
el.text(el.data("text-swap"));
el.data("text-swap", tmp);
});
Geoff Bourne# J UL Y 2 , 2 0 1 3
Peter, you confirmed what I was just now wondering. I vote for modified Way #1 then :)
Chris Coyier# J UL Y 2 , 2 0 1 3
Definitely better. Except I guess that it supposes that the event always swaps the text no matter what,
without testing the state. But this is so abstract anyway if we’re considering “what ifs” we’d need to get
way more complicated.
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 10/21
Peter Foti# J UL Y 2 , 2 0 1 3
@Chris, right. I was only addressing the swapping out text task, since your original example didn’t
include any particular conditions on swapping it. That logic could be added still, but ideally you would
probably want a separate variable to identify the “state”. If you key off of the text of the button, you
add complexity if you ever need to use localized text.
Check out this Pen!
MaxArt# J UL Y 2 , 2 0 1 3
I used to do this with vanilla Javascript.
@Chris Well that’s no different than the other ways, and the CSS-only method, while lovely, can’t even
do any better than that: on/off, that’s all.
klaus# J UL Y 4 , 2 0 1 3
Thank you, Peter! I was thinking the same all the time while reading the article. This should be the
default way to toggle something.
Nevertheless an interesting subject. I have often wondering if there is something simpler than doing it
by jquery and the answer seems still be no when i’m looking at the css solutions. There is no point of
which I would say: yeah, thats much cleaner and simpler than doing it by js. :(
A bit strange in my opinion – we have so much fancy new elements like video and special input fields,
but still no simple toggle element.
welovewebdesign# J UL Y 6 , 2 0 1 3
Here is the vanilla version :
var button = document.querySelectorAll("button")[0];
button.addEventListener('click', function() {
var text = this.textContent
this.textContent = this.dataset.textSwap
this.dataset.textSwap = text
}, false);
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 11/21
Ravindran# J UL Y 2 , 2 0 1 3
I was thinking same solution Peter Foti suggested. Here is my fiddle.
http://jsfiddle.net/rnavaneethan/Fax7D/1/embedded/result/
Austin M. Matherne# J UL Y 2 , 2 0 1 3
It would be overkill for just this rather basic example, but since it’s part of a larger web application, chances
are you should already be using one of the many client side MV* frameworks available. Regardless of if you
are manually wiring it up with a view yourself in backbone, or using a framework that binds them together
for you (such as Ember or Angular), it’s cleaner to store state in a model.
Benjamin C.# J UL Y 2 , 2 0 1 3
Just wanted to say that the first two javascripts snippets miss a closing parenthesis :
button.text(button.data("text-swap");
// should be
button.text(button.data("text-swap"));
Kellen Green# J UL Y 2 , 2 0 1 3
Love your work Chris. One possible shortcut for the JavaScript.
var button = document.querySelectorAll("button")[0];
// could be simplified with
var button = document.querySelector("button");
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 12/21
MaxArt# J UL Y 2 , 2 0 1 3
I guess he originally used getElementsByTagName and later changed it for some reason, but that’s
hardly the point.
I think we can read that line as “use the method that fits better for you to get that dang button
element!”
Sylvain# J UL Y 2 , 2 0 1 3
CSS second way (french touch)
input[type=checkbox].on-off{
appearance:none;
-webkit-appearance:none;
-moz-appearance:none;
}
input[type=checkbox].on-off:after{content:attr(data-unchecked);}
input[type=checkbox].on-off:checked:after{content:attr(data-checked);}
MaxArt# J UL Y 2 , 2 0 1 3
Nice, but what’s the French bit?
Also, if you feel confident to use :checked and appearance, you should also go for ::after (pseudo-
element) rather than :after (pseudo-class), as the only reason we still use that syntax is IE8…
Mahdi# J UL Y 3 , 2 0 1 3
This is the best way, no need for js with all css, also no HTML code in the css.
they only thing I will add is display: none for the checkbox because appearance is not supported in all
browsers.
also I would not put the input inside of the label, other than that this is great.
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 13/21
Sylvain# J UL Y 2 , 2 0 1 3
<label><input class=”on-off” type=”checkbox” data-checked=”oui” data-unchecked=”non” /></label>
Mike# J UL Y 2 , 2 0 1 3
Maybe i’m just weird but normally i set the text initially inside whatever HTML tag i’m using, then when
needed use jQuery to replace the content of that text with whatever new text. Like so:
$(“p”).text(“Hide”);
and then set it back to show when necessary
Is there a reason why this isn’t a good idea?
MaxArt# J UL Y 2 , 2 0 1 3
It isn’t because you should keep the content in the DOM rather than your code. To keep things clean
and separated, you know.
Your way – the traditional way – is definitely simpler, faster and uses less memory (but if you’re
concerned about these things for a task like this you shouldn’t even use jQuery). On the other hand,
when the project becomes larger, and you end up changing something, you may regret your decision.
Imagine you have two toggle buttons, but in the other one the words you must show are, for example,
“Start” and “Stop”: you have to write the code again for essentially the same task.
Repeat this ad libitum and you’ll get the idea.
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 14/21
Bradley# J UL Y 2 , 2 0 1 3
@Mike,
Reusability and separation of concerns. Let’s say you have two buttons that toggle text values, and one
toggles between Show/Hide and the second between Forward/Backward. Doing it your way, you have to
write two sets of JS for each, and associate the View code (i.e., the text displayed) in the code that manages
state (on/off).
Using data attributes or something similar, your JS doesn’t need to know what the text is – only the state,
and to toggle that on or off.
Surjith SM# J UL Y 2 , 2 0 1 3
I’m trying out the last CSS only version in my Dreamweaver. But its not working[chrome,firefox]. When I did
the same in codepen, its working find. What did I missed?
CSS
HTML
< input id=”example-checkbox” type=”checkbox”>
< label for=”example” id=”example”>Show < /label >
#example {
position: relative;
}
#example-checkbox {
display: none;
}
#example-checkbox:checked + #example:after {
content: "Hide";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: white;
}
zet# J UL Y 3 , 2 0 1 3
@Surjith
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 15/21
for attribute corrected
< label for=”example-checkbox” id=”example”>Show < /label >
Surjith SM# J UL Y 3 , 2 0 1 3
Thanks Zet.
It worked.
Given in the post is also mistakken.
Hristo Chakarov# J UL Y 3 , 2 0 1 3
http://jsfiddle.net/vmJ5h/
Mahdi# J UL Y 3 , 2 0 1 3
I Like the way you used the array to do two things for you :), Smart
Xavi# J UL Y 4 , 2 0 1 3
Can you explain me the array part of the code: [ el.text(), el.text( el.data(‘swap’) ) ][0]
Hristo Chakarov# J UL Y 4 , 2 0 1 3
The whole approach does not have any if-else statements as well as does not use a variable to store the
current text value. I’m using array with length=2 for that purpose. The first element of the array is the
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 16/21
current text value. Second element actually swaps the text value, using the new value from the data
attribute. As we already stored the initial value as first element in the array, we immediately access it via
[0]. And we use it to set the new value of the data attribute.
No “if”s, no variables, just 2 lines of code. Clean & simple.
Avi# J UL Y 3 , 2 0 1 3
Hi, Thanks for the sharing. I’m using the CSS only way in a new project I’m currently working on.
Btw I love your articles and tutos. :)
Paul# J UL Y 4 , 2 0 1 3
Have used jQuery, but mostly just use simplistic Vanilla…
Following can be applied to any number of elements directly.
<button onclick=”elementStateChange(this, [“Show”,”Hide”])”>Show</button>
function elementStateChange(which, display){
if (which.innerText == display[0]){
which.innerText =display[1] ;
}else{
which.innerText =display[0] ;
}
}
Show
Paul# J UL Y 4 , 2 0 1 3
Oops should have come out…
<script>
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 17/21
function elementStateChange(which, display){
if (which.innerText == display[0]){
}
</script>
<button onclick=’elementStateChange(this, [“Show”,”Hide”])’>Show</button>
which.innerText =display[1] ;
}else{
which.innerText =display[0] ;
}
Ramesh Chowdarapally# J UL Y 4 , 2 0 1 3
Useful info chris.
jsc42# J UL Y 4 , 2 0 1 3
@Paul
Even more compactly:
which.innerText = display[which.innerText == display[0] ? 1 : 0];
jsc42# J UL Y 4 , 2 0 1 3
The old way (works from MS-IE4 / NN4 to current day) is:
<input type=button value=Hide onclick="this.value = this.value == 'Hide' ?
'Show' : 'Hide';">
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 18/21
Karl# J UL Y 4 , 2 0 1 3
@Chris, @Peter
State can be seen by what is listed in the button. But I would’t really recommend this as you are binding the
view to state.
David Gilbertson# J UL Y 4 , 2 0 1 3
I’ve got a voice in the back of my head saying this is a bad idea, but another approach is to have two buttons.
This HTML:
This CSS:
..and the following jQuery:
Thoughts?
Hide
Show
#btn-show { display: none; }
$('.btn-show-or-hide').on( 'click', function () {
$('.btn-show-or-hide').toggle();
});
David Gilbertson# J UL Y 4 , 2 0 1 3
Fiddle for above: http://jsfiddle.net/davidg707/JNB2F/
Anthony# J UL Y 4 , 2 0 1 3
Regarding the CSS Way (with jQuery changing class names), you could use text-indent and not have to use a
background-color and overlay the text on top like that..
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 19/21
jason# J UL Y 7 , 2 0 1 3
Why not just toggle classes? There is often some HTML involved. Data attr isn’t enough always.
Ron# J UL Y 1 0 , 2 0 1 3
I noticed something cool with CSS Generated Content in Opera (before Chromium). The
property actually works on real elements, not just the pseudo before and after elements. Of course, this
doesn’t work in any other browser else, and I’m not even sure that the specification calls for this.
Just seeing your :after usage made me remember, is all. :)
content
Jon# AUG UST 2 1 , 2 0 1 3
I’ve just done this with a mixture of both jQuery and Vanilla by creating a function that passes both the
target to check state (as per most text swaps are built for) and the text to swap:
changeDisplayText = function(targetId, displayText){
Result
Edit on
Anonymous Pens can't be embedded.
Edit on CodePen
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 20/21
and then call it like this:
and
Thoughts?
return displayText = targetId.is(":visible") ? displayText.replace("Hide","Show") : displayText.replace("Show","Hide");
}
$(this).attr('title', changeDisplayText($(this.hash), $(this).attr('title')));
$(this).html(changeDisplayText($(this.hash), $(this).html()));
Даниил# NO V E M B E R 1 1 , 2 0 1 3
We need to store data into variables before swap it.
I suggest to use an element without text in HTML:
And this JS to make it live:
I created a pen for it: cdpn.io/yEJdw
button.toggle(data-swap="close", data-text="open")
var button = $(".toggle");
button.html(button.data("text"));
button.click(function(){
var el = $(this);
var swap = el.data("swap");
var text = el.data("text");
el.data("text", swap);
el.data("swap", text);
el.html(swap);
});
eadly# M AR C H 2 9 , 2 0 1 4
nice ways i like css way but Sometimes we are forced to use other ways
1/14/2015 Swapping Out Text, Five Different Ways | CSS-Tricks
http://css-tricks.com/swapping-out-text-five-different-ways/ 21/21
*May or may not contain any actual "CSS" or "Tricks".
Carol Jenkins# AP R I L 2 4 , 2 0 1 4
How do you get the data attribute to persist on page refresh?
This comment thread is closed. If you have important information to share, you can always contact me.