Anda di halaman 1dari 21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-Tricks

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:
HTML
<button data-text-swap="Show">Hide</button>

It's easy to swap out the text, like:


jQuery
var button = $("button");
button.text(button.data("text-swap"));

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.
jQuery
var button = $("button");
button.data("text-original", button.text());
button.text(button.data("text-swap"));

To do that on a click event, you'd do:


jQuery
var button = $("button");
button.on("click", function() {
button.data("text-original", button.text());
http://css-tricks.com/swapping-out-text-five-different-ways/

1/21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-Tricks

button.text(button.data("text-swap"));
});

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
$("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 Way (More Markup / Less JavaScript)


If we're willing to set that data-text-original 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.
jQuery
$("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"));
});

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:
JavaScript
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 {
http://css-tricks.com/swapping-out-text-five-different-ways/

2/21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-Tricks

button.setAttribute("data-text-original", button.innerHTML);
button.innerHTML = button.getAttribute("data-text-swap");
}
}, false);

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.
CSS
a{
position: relative;
}
a.on:after {
content: "Hide";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: white;
}

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
:checked 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.

http://css-tricks.com/swapping-out-text-five-different-ways/

3/21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-Tricks

HTML
<input id="example-checkbox" type="checkbox">
<label for="example" id="example">Show</label>

CSS
#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;
}

Demo of All Five Ways

http://css-tricks.com/swapping-out-text-five-different-ways/

4/21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-Tricks

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


Show

CSS Only Way


Show

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
http://css-tricks.com/swapping-out-text-five-different-ways/

5/21

1/14/2015

http://css-tricks.com/swapping-out-text-five-different-ways/

Swapping Out Text, Five Different Ways | CSS-Tricks

6/21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-Tricks

Comments
Matt Litherland
# J UL Y 2 , 2 0 1 3
Nice article Chris, im using this right now on a CodePen :-)

Subash
# J UL Y 2 , 2 0 1 3
What about using attr() in css to get data from html instead of hard coding that.
<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.

http://css-tricks.com/swapping-out-text-five-different-ways/

7/21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-Tricks

Litek
# J UL Y 2 , 2 0 1 3
Whenever I swap things even single word I use js only to switch classes:
<span class="btn show-default">
<span "text-default">show</span>
<span "text-altered">hide</span>
</span>
and css:
.show-default > .text-altered { display:none; }
.show-altered > .text-default { display:none; }
More markup, less js but feels better:)

Chris Coyier
# J UL Y 2 , 2 0 1 3
Yah with display: none; I guess its not even an accessibility concern really eh?

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:
http://css-tricks.com/swapping-out-text-five-different-ways/

8/21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-Tricks

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);
Of course, that wont work in IE < 11, but we can dream :(

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 were considering what ifs wed need to get
way more complicated.

http://css-tricks.com/swapping-out-text-five-different-ways/

9/21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-Tricks

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 didnt
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 thats no different than the other ways, and the CSS-only method, while lovely, cant even
do any better than that: on/off, thats 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 im 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);
http://css-tricks.com/swapping-out-text-five-different-ways/

10/21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-Tricks

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 its 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), its 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");

http://css-tricks.com/swapping-out-text-five-different-ways/

11/21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-Tricks

MaxArt
# J UL Y 2 , 2 0 1 3
I guess he originally used getElementsByTagName and later changed it for some reason, but thats
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 whats the French bit?
Also, if you feel confident to use :checked and appearance, you should also go for ::after (pseudoelement) 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.

http://css-tricks.com/swapping-out-text-five-different-ways/

12/21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-Tricks

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 im just weird but normally i set the text initially inside whatever HTML tag im 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 isnt a good idea?

MaxArt
# J UL Y 2 , 2 0 1 3
It isnt 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 youre
concerned about these things for a task like this you shouldnt 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 youll get the idea.

http://css-tricks.com/swapping-out-text-five-different-ways/

13/21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-Tricks

Bradley
# J UL Y 2 , 2 0 1 3
@Mike,
Reusability and separation of concerns. Lets 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 doesnt 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
Im 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
#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;
}
HTML
< input id=example-checkbox type=checkbox>
< label for=example id=example>Show < /label >

zet
# J UL Y 3 , 2 0 1 3
@Surjith
http://css-tricks.com/swapping-out-text-five-different-ways/

14/21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-Tricks

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. Im using array with length=2 for that purpose. The first element of the array is the
http://css-tricks.com/swapping-out-text-five-different-ways/

15/21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-Tricks

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 ifs, no variables, just 2 lines of code. Clean & simple.

Avi
# J UL Y 3 , 2 0 1 3
Hi, Thanks for the sharing. Im using the CSS only way in a new project Im 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>
http://css-tricks.com/swapping-out-text-five-different-ways/

16/21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-Tricks

function elementStateChange(which, display){


if (which.innerText == display[0]){
which.innerText =display[1] ;
}else{
which.innerText =display[0] ;
}
}
</script>
<button onclick=elementStateChange(this, [Show,Hide])>Show</button>

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';">

http://css-tricks.com/swapping-out-text-five-different-ways/

17/21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-Tricks

Karl
# J UL Y 4 , 2 0 1 3
@Chris, @Peter
State can be seen by what is listed in the button. But I wouldt really recommend this as you are binding the
view to state.

David Gilbertson
# J UL Y 4 , 2 0 1 3
Ive 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:
Hide
Show
This CSS:
#btn-show { display: none; }
..and the following jQuery:
$('.btn-show-or-hide').on( 'click', function () {
$('.btn-show-or-hide').toggle();
});
Thoughts?

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..

http://css-tricks.com/swapping-out-text-five-different-ways/

18/21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-Tricks

Result

Edit on

Anonymous Pens can't be embedded.


Edit on CodePen

jason
# J UL Y 7 , 2 0 1 3
Why not just toggle classes? There is often some HTML involved. Data attr isnt 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 content
property actually works on real elements, not just the pseudo before and after elements. Of course, this
doesnt work in any other browser else, and Im not even sure that the specification calls for this.
Just seeing your :after usage made me remember, is all. :)

Jon
# AUG UST 2 1 , 2 0 1 3
Ive 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){
http://css-tricks.com/swapping-out-text-five-different-ways/

19/21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-Tricks

return displayText = targetId.is(":visible") ? displayText.replace("Hide","Show") :


}

and then call it like this:


$(this).attr('title', changeDisplayText($(this.hash), $(this).attr('title')));

and
$(this).html(changeDisplayText($(this.hash), $(this).html()));
Thoughts?

# 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:
button.toggle(data-swap="close", data-text="open")
And this JS to make it live:
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);
});
I created a pen for it: cdpn.io/yEJdw

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

http://css-tricks.com/swapping-out-text-five-different-ways/

20/21

1/14/2015

Swapping Out Text, Five Different Ways | CSS-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.

*May or may not contain any actual "CSS" or "Tricks".

http://css-tricks.com/swapping-out-text-five-different-ways/

21/21

Anda mungkin juga menyukai