jQuery / Method / .toggle() - 선택한 요소가 보이면 보이지 않게, 보이지 않으면 보이게 하는 메서드
jQuery의 .toggle()은 선택한 각 요소가 표시 중이면 숨기고 숨겨져 있으면 표시합니다. .toggle(true)는 표시, .toggle(false)는 숨김을 지정하며, .toggle(800)처럼 시간을 주면 애니메이션으로 전환합니다. 상태를 반전할지 원하는 상태를 명시할지에 따라 호출 형태를 구분합니다.
즉시 반전·상태 지정·애니메이션의 차이
.toggle() 공식 문서에서 인수 없는 호출은 display를 바꿔 즉시 표시·숨김을 전환합니다. 처음 Alpha만 보이고 Beta가 숨겨졌다면 한 번 호출한 뒤 Alpha는 숨고 Beta는 보입니다. 집합 전체를 같은 상태로 맞추는 의미가 아닙니다.
| 호출 | 동작 | 사용 기준 |
|---|---|---|
| .toggle() | 각 요소의 표시 상태 반전 | 현재 상태를 뒤집을 때 |
| .toggle(true)·.toggle(false) | 표시·숨김을 명시 | 원하는 상태가 정해졌을 때 |
| .toggle(800) | 800ms 동안 전환 | 크기와 투명도 변화가 필요할 때 |
| .toggle({ duration: 0, complete: 함수 }) | 시간 0인 효과 경로 | 즉시 끝내되 완료 처리가 필요할 때 |
시간을 지정한 효과는 너비·높이·투명도를 함께 바꾸며 숨김이 끝나면 display:none이 되어 배치 공간도 사라집니다. 800은 밀리초이므로 0.8초이며 값이 클수록 느립니다. 불리언 false와 숫자 0은 서로 다른 호출 형태입니다. 입력값 같은 DOM(Document Object Model, 문서 객체 모델) 상태는 숨겼다는 이유만으로 삭제되지 않습니다.
두 패널로 확인하는 전체 예제
전체 코드를 UTF-8로 toggle-demo.html에 저장하고 브라우저로 엽니다. 인터넷으로 콘텐츠 전송망(CDN)의 공식 jQuery 전체 파일 4.0.0을 읽습니다. 시간 지정 효과는 effects 모듈이 필요하므로 slim 파일로 바꾸지 않습니다. 아래 전환·초기화와 콘솔 예제를 3.7.1·4.0.0에서 실행했습니다.
Alpha는 flex로 표시되고 Beta는 처음 숨겨져 있습니다. 조작 버튼은 숨길 패널 밖에 두었습니다. 모드에서 즉시·800ms·200ms·0ms를 고를 수 있고, 효과 중에는 busy로 추가 전환 요청을 무시합니다. 시스템의 동작 줄이기 설정이면 선택한 효과의 시간을 0으로 적용합니다.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Toggle each panel visibility</title>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<style>
body { font: 16px/1.6 sans-serif; max-width: 760px; margin: 24px auto; padding: 16px; }
button, select, input { font: inherit; margin: 4px; max-width: 100%; box-sizing: border-box; }
.panel { padding: 12px; margin: 10px 0; border: 1px solid teal; background: #edf9f6; }
#alpha { display: flex; flex-wrap: wrap; align-items: center; }
#beta { display: none; }
pre { white-space: pre-wrap; overflow-wrap: anywhere; }
</style>
</head>
<body>
<h1>Toggle independently or set a known state</h1>
<label for="mode">Mode:</label>
<select id="mode"><option value="instant">No arguments</option><option value="800">800ms</option><option value="200">200ms</option><option value="0">0ms</option></select>
<button type="button" id="toggle">Toggle each</button>
<button type="button" id="show">Show both</button>
<button type="button" id="hide">Hide both</button>
<button type="button" id="reset">Reset</button>
<div id="panels">
<div class="panel" id="alpha">Alpha <input aria-label="Alpha note" value="Keep this note"></div>
<div class="panel" id="beta">Beta panel</div>
</div>
<pre id="result" aria-live="polite"></pre>
<script>
$(function () {
const $panels = $("#panels > .panel");
let busy = false, completed = 0;
function report() {
const visible = $panels.filter(":visible").map(function () { return this.id; }).get();
$("#result").text(`visible=${visible.join(",") || "(none)"}\ncompleted=${completed}\nbusy=${busy}\nDOM panels=${$panels.length}`);
}
function settle() { $panels.stop(true, true); busy = false; completed = 0; }
$("#toggle").on("click", function () {
if (busy) return;
completed = 0;
const mode = $("#mode").val();
if (mode === "instant") { $panels.toggle(); report(); return; }
if (!$panels.length) { report(); return; }
busy = true; report();
const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
$panels.toggle({ duration: reduced ? 0 : Number(mode), complete: function () {
completed++;
if (completed === $panels.length) busy = false;
report();
} });
});
$("#show").on("click", function () { settle(); $panels.toggle(true); report(); });
$("#hide").on("click", function () { settle(); $panels.toggle(false); report(); });
$("#reset").on("click", function () {
settle(); $("#alpha").toggle(true); $("#beta").toggle(false);
$("#alpha input").val("Keep this note"); $("#mode").val("instant"); report();
});
report();
});
</script>
</body>
</html>
처음에는 Alpha만 보이며 두 패널은 문서에 모두 남습니다.
visible=alpha
completed=0
busy=false
DOM panels=2
- No arguments에서 Toggle each를 누르면 Beta만 보이고 completed는 0입니다. 다시 누르면 Alpha로 돌아옵니다.
- Alpha 입력값을 수정한 뒤 숨기고 다시 표시하면 편집값이 남습니다. flex 표시도 복원되는지 확인합니다.
- 800ms를 골라 전환하면 완료 뒤 visible=beta, completed=2, busy=false입니다. 콜백은 집합 전체에 한 번이 아니라 각 패널에 한 번씩 실행됩니다.
- 효과 중 여러 번 눌러도 이 예제는 요청을 무시해 전환이 대기열에 계속 쌓이지 않습니다. 200ms와 비교할 때는 Reset 후 같은 초기 상태에서 시작합니다.
- Show both는 모두 표시하고 Hide both는 모두 숨깁니다. 여러 번 눌러도 같은 상태를 유지합니다.
- Reset은 진행 효과를 정리한 뒤 Alpha 표시·Beta 숨김, 기본 입력값과 모드를 복원합니다. 따라서 입력값이 바뀌는 것은 숨김 때문이 아니라 Reset의 명시적 .val() 처리 때문입니다.
0ms 모드는 인수 없는 호출과 화면상 비슷해도 complete가 패널마다 실행되어 completed=2입니다. 동작 줄이기도 같은 경로를 사용하며, 이 예제를 위해 사이트 전체의 전역 효과 설정을 바꾸지는 않습니다. 애니메이션 도중의 :visible은 최종 상태와 같다고 단정하지 말고 필요한 결과는 완료 뒤 확인합니다.
불리언과 실행 중 초기화
조건의 결과로 표시 여부를 정할 때는 실제 불리언 값을 전달합니다. true를 두 번 줘도 다시 숨겨지지 않습니다. 다음 코드를 같은 페이지의 개발자 도구 Console에서 실행하면 독립 임시 요소 두 개로 확인한 뒤 제거합니다.
const $holder = $('<div><p>A</p><p>B</p></div>').appendTo("body");
const $items = $holder.find("p");
$items.toggle(false);
$items.toggle(false);
console.log(`hide twice visible=${$items.filter(":visible").length}`);
$items.toggle(true);
$items.toggle(true);
console.log(`show twice visible=${$items.filter(":visible").length}`);
console.log(`DOM count=${$items.length}`);
$holder.remove();
hide twice visible=0
show twice visible=2
DOM count=2
애니메이션을 진행하던 중 상태를 강제로 맞추려면 대기열과 내부 효과 상태를 함께 고려합니다. 예제의 settle()은 .stop(true, true)로 대기열을 비우고 현재 효과를 끝낸 다음 busy·completed를 초기화합니다. 두 번째 true 때문에 완료 콜백이 즉시 실행될 수 있으므로 카운터 초기화는 stop 호출 뒤에 둡니다.
Reset은 그 다음에 알려진 표시 상태를 지정합니다. 중간 크기에서 멈추는 동작과 최종 상태까지 마치는 동작은 다릅니다. 이 예제에서는 실행 중 Reset 후 바로 인수 없는 전환을 눌러도 Alpha에서 Beta로 정상 전환되는지까지 확인했습니다. 다른 정책으로 빠른 클릭을 처리하려면 무시·대기·현재 효과 종료 중 무엇을 원하는지 먼저 정합니다.
표시되지 않거나 효과가 다를 때
선택자와 .length, jQuery 로딩 오류를 먼저 확인합니다. 상위 요소가 display:none이면 자식에 .toggle(true)를 호출해도 화면에서 보이지 않을 수 있습니다. visibility:hidden·opacity:0과 display:none도 구분합니다. .toggle()이 임의의 모든 숨김 원인이나 다른 스타일을 자동 해제하는 메서드는 아닙니다.
전환이 즉시 끝나면 선택 시간, 동작 줄이기 설정과 사용하는 빌드를 확인합니다. 크기를 바꾸지 않고 투명도만 전환하려는지, 높이만 접으려는지도 구분해 효과를 선택합니다. 효과 중 현재 너비·높이를 반복해서 읽어 영구 스타일로 덮어쓰면 복원이 어긋날 수 있으므로 목적 없이 섞지 않습니다.
실제 인터페이스에서 포커스가 있는 영역을 숨길 때는 다시 조작할 버튼과 포커스 이동을 함께 설계합니다. 이 예제는 컨트롤을 패널 밖에 유지하지만 포커스 복원이나 펼침 상태 안내 전체를 구현한 구성 요소는 아닙니다. .toggle()의 표시 기능만으로 인터페이스의 모든 상호작용이 완성됐다고 판단하지 않습니다.




