コピー成功
コードをコピーすると「Copied!」の吹き出しがポンと弾んで現れチェックマークに切り替わり、数秒でふわっと消えるコピーボタン。
ライブデモ
コード
HTML
<!-- コピー成功: コピー操作でCopied!ツールチップが弾んで現れ、チェックマークに切り替わって数秒で消える -->
<div class="stage">
<div class="copy-field">
<code class="copy-field__code">npm install wedelab-ui</code>
<button class="copy-field__btn" type="button" aria-label="コードをコピー">
<svg class="copy-field__icon copy-field__icon--copy" viewBox="0 0 24 24" aria-hidden="true">
<rect x="8" y="7" width="11" height="13" rx="2" fill="none" stroke="currentColor" stroke-width="1.8"/>
<path d="M5.5 16V5.5a1 1 0 0 1 1-1H16" fill="none" stroke="currentColor" stroke-width="1.8"/>
</svg>
<svg class="copy-field__icon copy-field__icon--check" viewBox="0 0 24 24" aria-hidden="true">
<path d="M5 13l4.5 4.5L19 8" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span class="copy-field__tooltip" role="status">Copied!</span>
</button>
</div>
<p class="hint">クリックでコマンドをコピーします</p>
</div>
CSS
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
overflow: hidden;
display: grid;
place-items: center;
font-family: "Segoe UI", system-ui, sans-serif;
background: radial-gradient(circle at 50% 30%, #1b1830 0%, #0d0e1a 72%);
color: #f4f5fb;
}
.stage { display: grid; place-items: center; gap: 16px; padding: 20px; }
.copy-field {
display: inline-flex;
align-items: center;
gap: 4px;
max-width: min(86vw, 300px);
padding: 6px 6px 6px 18px;
border-radius: 14px;
background: rgba(255, 255, 255, .05);
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .09), 0 10px 24px rgba(0, 0, 0, .4);
}
.copy-field__code {
flex: 1 1 auto;
min-width: 0;
font: 500 13.5px/1 "Cascadia Code", "Consolas", monospace;
color: #cdd3f0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
letter-spacing: .01em;
}
.copy-field__btn {
position: relative;
flex: none;
border: none;
cursor: pointer;
width: 38px;
height: 38px;
border-radius: 10px;
display: grid;
place-items: center;
color: #cdd3f0;
background: rgba(255, 255, 255, .07);
-webkit-tap-highlight-color: transparent;
transition: transform .12s ease;
animation: copy-idle 3s ease-in-out infinite;
}
.copy-field__btn:active { transform: scale(.9); }
.copy-field__btn:focus-visible { outline: 2px solid #a78bfa; outline-offset: 3px; }
@keyframes copy-idle {
0%, 100% { box-shadow: 0 0 0 rgba(167, 139, 250, 0); }
50% { box-shadow: 0 0 10px rgba(167, 139, 250, .38); }
}
.copy-field__icon {
position: absolute;
top: 50%;
left: 50%;
width: 19px;
height: 19px;
transform: translate(-50%, -50%) scale(1);
transition: opacity .22s ease, transform .35s cubic-bezier(.34, 1.56, .64, 1);
}
.copy-field__icon--check {
opacity: 0;
color: #22c55e;
transform: translate(-50%, -50%) scale(.4);
}
.copy-field__btn.is-copied .copy-field__icon--copy {
opacity: 0;
transform: translate(-50%, -50%) scale(.4);
}
.copy-field__btn.is-copied .copy-field__icon--check {
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
.copy-field__tooltip {
position: absolute;
left: 50%;
bottom: calc(100% + 10px);
transform: translate(-50%, 6px) scale(.5);
opacity: 0;
padding: 6px 12px;
border-radius: 10px;
background: #201c38;
color: #f4f5fb;
font: 700 12.5px/1 "Segoe UI", system-ui, sans-serif;
white-space: nowrap;
box-shadow: 0 8px 20px rgba(0, 0, 0, .5), inset 0 0 0 1px rgba(255, 255, 255, .09);
pointer-events: none;
transition: opacity .22s ease, transform .22s ease;
}
.copy-field__tooltip::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
border: 5px solid transparent;
border-top-color: #201c38;
}
.copy-field__btn.is-copied .copy-field__tooltip {
opacity: 1;
transform: translate(-50%, 0) scale(1);
transition: opacity .3s ease, transform .5s cubic-bezier(.34, 1.56, .64, 1);
}
.hint { margin: 0; font-size: 13px; color: rgba(244, 245, 251, .5); text-align: center; }
@media (prefers-reduced-motion: reduce) {
.copy-field__btn { animation: none; }
.copy-field__icon,
.copy-field__tooltip { transition-duration: .12s; }
.copy-field__btn.is-copied .copy-field__tooltip { transition-duration: .12s; }
}
JavaScript
// コピー成功: クリックでクリップボードへコピーし、Copied!ツールチップを弾ませて表示する
(() => {
const btn = document.querySelector('.copy-field__btn');
const codeEl = document.querySelector('.copy-field__code');
if (!btn || !codeEl) return; // null安全
let hideTimer = null;
const showFeedback = () => {
btn.classList.remove('is-copied');
void btn.offsetWidth; // reflow: 連続クリックでも毎回弾ませる
btn.classList.add('is-copied');
window.clearTimeout(hideTimer);
hideTimer = window.setTimeout(() => btn.classList.remove('is-copied'), 1700);
};
btn.addEventListener('click', () => {
const text = codeEl.textContent || '';
// サンドボックスiframe等でクリップボード権限がなくても、見た目のフィードバックは必ず出す
try {
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).catch(() => {});
}
} catch (e) {
/* 権限なし・非対応環境は無視 */
}
showFeedback();
});
})();
🤖 AIエージェント用プロンプト
このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「コピー成功」の効果を追加してください。
# 追加してほしい効果
コピー成功(遊べるUI)
コードをコピーすると「Copied!」の吹き出しがポンと弾んで現れチェックマークに切り替わり、数秒でふわっと消えるコピーボタン。
# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】
# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- コピー成功: コピー操作でCopied!ツールチップが弾んで現れ、チェックマークに切り替わって数秒で消える -->
<div class="stage">
<div class="copy-field">
<code class="copy-field__code">npm install wedelab-ui</code>
<button class="copy-field__btn" type="button" aria-label="コードをコピー">
<svg class="copy-field__icon copy-field__icon--copy" viewBox="0 0 24 24" aria-hidden="true">
<rect x="8" y="7" width="11" height="13" rx="2" fill="none" stroke="currentColor" stroke-width="1.8"/>
<path d="M5.5 16V5.5a1 1 0 0 1 1-1H16" fill="none" stroke="currentColor" stroke-width="1.8"/>
</svg>
<svg class="copy-field__icon copy-field__icon--check" viewBox="0 0 24 24" aria-hidden="true">
<path d="M5 13l4.5 4.5L19 8" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span class="copy-field__tooltip" role="status">Copied!</span>
</button>
</div>
<p class="hint">クリックでコマンドをコピーします</p>
</div>
【CSS】
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
overflow: hidden;
display: grid;
place-items: center;
font-family: "Segoe UI", system-ui, sans-serif;
background: radial-gradient(circle at 50% 30%, #1b1830 0%, #0d0e1a 72%);
color: #f4f5fb;
}
.stage { display: grid; place-items: center; gap: 16px; padding: 20px; }
.copy-field {
display: inline-flex;
align-items: center;
gap: 4px;
max-width: min(86vw, 300px);
padding: 6px 6px 6px 18px;
border-radius: 14px;
background: rgba(255, 255, 255, .05);
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .09), 0 10px 24px rgba(0, 0, 0, .4);
}
.copy-field__code {
flex: 1 1 auto;
min-width: 0;
font: 500 13.5px/1 "Cascadia Code", "Consolas", monospace;
color: #cdd3f0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
letter-spacing: .01em;
}
.copy-field__btn {
position: relative;
flex: none;
border: none;
cursor: pointer;
width: 38px;
height: 38px;
border-radius: 10px;
display: grid;
place-items: center;
color: #cdd3f0;
background: rgba(255, 255, 255, .07);
-webkit-tap-highlight-color: transparent;
transition: transform .12s ease;
animation: copy-idle 3s ease-in-out infinite;
}
.copy-field__btn:active { transform: scale(.9); }
.copy-field__btn:focus-visible { outline: 2px solid #a78bfa; outline-offset: 3px; }
@keyframes copy-idle {
0%, 100% { box-shadow: 0 0 0 rgba(167, 139, 250, 0); }
50% { box-shadow: 0 0 10px rgba(167, 139, 250, .38); }
}
.copy-field__icon {
position: absolute;
top: 50%;
left: 50%;
width: 19px;
height: 19px;
transform: translate(-50%, -50%) scale(1);
transition: opacity .22s ease, transform .35s cubic-bezier(.34, 1.56, .64, 1);
}
.copy-field__icon--check {
opacity: 0;
color: #22c55e;
transform: translate(-50%, -50%) scale(.4);
}
.copy-field__btn.is-copied .copy-field__icon--copy {
opacity: 0;
transform: translate(-50%, -50%) scale(.4);
}
.copy-field__btn.is-copied .copy-field__icon--check {
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
.copy-field__tooltip {
position: absolute;
left: 50%;
bottom: calc(100% + 10px);
transform: translate(-50%, 6px) scale(.5);
opacity: 0;
padding: 6px 12px;
border-radius: 10px;
background: #201c38;
color: #f4f5fb;
font: 700 12.5px/1 "Segoe UI", system-ui, sans-serif;
white-space: nowrap;
box-shadow: 0 8px 20px rgba(0, 0, 0, .5), inset 0 0 0 1px rgba(255, 255, 255, .09);
pointer-events: none;
transition: opacity .22s ease, transform .22s ease;
}
.copy-field__tooltip::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
border: 5px solid transparent;
border-top-color: #201c38;
}
.copy-field__btn.is-copied .copy-field__tooltip {
opacity: 1;
transform: translate(-50%, 0) scale(1);
transition: opacity .3s ease, transform .5s cubic-bezier(.34, 1.56, .64, 1);
}
.hint { margin: 0; font-size: 13px; color: rgba(244, 245, 251, .5); text-align: center; }
@media (prefers-reduced-motion: reduce) {
.copy-field__btn { animation: none; }
.copy-field__icon,
.copy-field__tooltip { transition-duration: .12s; }
.copy-field__btn.is-copied .copy-field__tooltip { transition-duration: .12s; }
}
【JavaScript】
// コピー成功: クリックでクリップボードへコピーし、Copied!ツールチップを弾ませて表示する
(() => {
const btn = document.querySelector('.copy-field__btn');
const codeEl = document.querySelector('.copy-field__code');
if (!btn || !codeEl) return; // null安全
let hideTimer = null;
const showFeedback = () => {
btn.classList.remove('is-copied');
void btn.offsetWidth; // reflow: 連続クリックでも毎回弾ませる
btn.classList.add('is-copied');
window.clearTimeout(hideTimer);
hideTimer = window.setTimeout(() => btn.classList.remove('is-copied'), 1700);
};
btn.addEventListener('click', () => {
const text = codeEl.textContent || '';
// サンドボックスiframe等でクリップボード権限がなくても、見た目のフィードバックは必ず出す
try {
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).catch(() => {});
}
} catch (e) {
/* 権限なし・非対応環境は無視 */
}
showFeedback();
});
})();
# 外部ライブラリ
なし(追加ライブラリ不要)
# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。