T-005 Toggle medium

Neon Cyber Billing Switch ネオン請求切り替えスイッチ

Glowing neon styled billing cycle switch with annual discount indicators and instant tier price updates. 月額と年額の切り替えで割引価格とバッジが更新されるネオンUI。

ライブデモ Live Demo

Neon Cloud Tier

Developer
$15/mo

Standard fast isolated container instances.

Enterprise
$89/mo

Dedicated compute clusters and SLAs.

Billed monthly. Fictional demo prices.

概要・用途・特徴Overview, Usage & Features

何ができるかWhat it does

Glowing neon styled billing cycle switch with annual discount indicators and instant tier price updates.

月額と年額の切り替えで割引価格とバッジが更新されるネオンUI。

どこで使うかWhere to use

Portfolio, product showcase, landing page.

ポートフォリオ、製品紹介、ランディングページ。

特徴Key features

Glowing neon styled billing cycle switch with annual discount indicators and instant tier price updates.

月額と年額の切り替えで割引価格とバッジが更新されるネオンUI。

調整可能パラメータ Adjustable Parameters

Parameter Default Description
--demo-accent#c084fcAccent color for the panel border and keyboard focus ring.

実装コード Implementation Code

<div class="demo-stage nb-root" role="region" aria-label="Billing Cycle Selector"><div class="nb-panel"><div class="nb-header"><h3 class="nb-title">Neon Cloud Tier</h3><div class="nb-toggle-wrap" role="group" aria-label="Billing frequency"><button type="button" class="nb-cycle-btn nb-active" data-cycle="monthly" aria-pressed="true" aria-label="Select monthly billing">Monthly</button><button type="button" class="nb-cycle-btn" data-cycle="annual" aria-pressed="false" aria-label="Select annual billing with discount">Annual <span class="nb-badge">SAVE 20%</span></button></div></div><div class="nb-grid"><div class="nb-tier-card" data-monthly="15" data-annual="12"><span class="nb-tier-name">Developer</span><div class="nb-tier-price"><span class="nb-currency">$</span><span class="nb-val">15</span><span class="nb-unit">/mo</span></div><p class="nb-tier-detail">Standard fast isolated container instances.</p></div><div class="nb-tier-card nb-featured" data-monthly="39" data-annual="31.20"><div class="nb-popular-tag">POPULAR</div><span class="nb-tier-name">Startup</span><div class="nb-tier-price"><span class="nb-currency">$</span><span class="nb-val">39</span><span class="nb-unit">/mo</span></div><p class="nb-tier-detail">High performance edge global distribution.</p></div><div class="nb-tier-card" data-monthly="89" data-annual="71.20"><span class="nb-tier-name">Enterprise</span><div class="nb-tier-price"><span class="nb-currency">$</span><span class="nb-val">89</span><span class="nb-unit">/mo</span></div><p class="nb-tier-detail">Dedicated compute clusters and SLAs.</p></div><p class="nb-billing-note" aria-live="polite">Billed monthly. Fictional demo prices.</p></div></div></div>
<script>
document.querySelectorAll('.nb-root').forEach(root => {
  const cycleBtns = root.querySelectorAll('.nb-cycle-btn');
  const cards = root.querySelectorAll('.nb-tier-card');
  if (!cycleBtns.length || !cards.length) return;
  cycleBtns.forEach(btn => {
    btn.addEventListener('click', () => {
      cycleBtns.forEach(b => {
        b.classList.remove('nb-active');
        b.setAttribute('aria-pressed', 'false');
      });
      btn.classList.add('nb-active');
      btn.setAttribute('aria-pressed', 'true');
      const cycle = btn.dataset.cycle; const note = root.querySelector('.nb-billing-note'); if(note) note.textContent = cycle === 'annual' ? 'Monthly equivalent, billed annually. Fictional demo prices.' : 'Billed monthly. Fictional demo prices.';
      cards.forEach(card => {
        const valEl = card.querySelector('.nb-val');
        if (valEl) {
          valEl.textContent = card.dataset[cycle];
        }
      });
    });
  });
});
</script>
.nb-root {
  box-sizing: border-box;
  width: 100%;
  max-width: 560px;
  max-height: 420px;
  min-width: 0;
  margin: 0 auto;
  padding: 16px;
  background: radial-gradient(circle at 50% 10%, #150d24 0%, #07050d 100%);
  border-radius: 16px;
  border: 1px solid #2e1c4a;
  box-shadow: 0 16px 36px rgba(0, 0, 0, 0.7);
  font-family: system-ui, -apple-system, sans-serif;
  color: #f1e8ff;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.nb-root *, .nb-root *::before, .nb-root *::after {
  box-sizing: border-box;
  min-width: 0;
}
.nb-root .nb-panel {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.nb-root .nb-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
}
.nb-root .nb-title {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  color: #ffffff;
  text-shadow: 0 0 10px rgba(168, 85, 247, 0.6);
}
.nb-root .nb-toggle-wrap {
  display: flex;
  background: #11091e;
  padding: 3px;
  border-radius: 10px;
  border: 1px solid #3b1d63;
}
.nb-root .nb-cycle-btn {
  appearance: none;
  border: none;
  background: transparent;
  color: #a78bfa;
  padding: 6px 14px;
  border-radius: 8px;
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 6px;
}
.nb-root .nb-cycle-btn.nb-active {
  background: #7e22ce;
  color: #ffffff;
  box-shadow: 0 0 12px rgba(126, 34, 206, 0.8);
}
.nb-root .nb-cycle-btn:focus-visible {
  outline: 2px solid #c084fc;
  outline-offset: 2px;
}
.nb-root .nb-badge {
  font-size: 9px;
  background: #06b6d4;
  color: #041f28;
  font-weight: 800;
  padding: 2px 5px;
  border-radius: 4px;
}
.nb-root .nb-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 10px;
}
.nb-root .nb-tier-card {
  position: relative;
  background: #130a21;
  border: 1px solid #2d1847;
  border-radius: 10px;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.nb-root .nb-tier-card.nb-featured {
  border-color: #a855f7;
  box-shadow: 0 0 16px rgba(168, 85, 247, 0.25);
}
.nb-root .nb-popular-tag {
  position: absolute;
  top: -8px;
  right: 10px;
  background: #a855f7;
  color: #ffffff;
  font-size: 8px;
  font-weight: 800;
  padding: 2px 6px;
  border-radius: 4px;
  letter-spacing: 0.5px;
}
.nb-root .nb-tier-name {
  font-size: 13px;
  font-weight: 700;
  color: #c084fc;
}
.nb-root .nb-tier-price {
  font-size: 22px;
  font-weight: 800;
  color: #ffffff;
  display: flex;
  align-items: baseline;
}
.nb-root .nb-currency {
  font-size: 14px;
  color: #d8b4fe;
}
.nb-root .nb-unit {
  font-size: 11px;
  color: #8b5cf6;
  font-weight: 500;
}
.nb-root .nb-tier-detail {
  margin: 0;
  font-size: 10px;
  color: #a78bfa;
  line-height: 1.3;
}
@media (prefers-reduced-motion: no-preference) {
  .nb-root .nb-cycle-btn {
    transition: background 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
  }
  .nb-root .nb-tier-card {
    transition: border-color 0.2s ease, transform 0.2s ease;
  }
  .nb-root .nb-val {
    transition: transform 0.2s ease;
  }
}
.nb-root{max-height:none;--demo-accent:#c084fc;border-color:var(--demo-accent)}.nb-root button:focus-visible{outline-color:var(--demo-accent)}
.nb-root .nb-billing-note{font-size:10px;color:#c4b5fd;margin:0}.nb-root .nb-grid{grid-template-columns:repeat(3,minmax(0,1fr))}.nb-root .nb-tier-card{padding:10px 8px}.nb-root .nb-tier-name{font-size:clamp(10px,2.5vw,13px)}.nb-root .nb-tier-price{font-size:clamp(17px,4vw,22px)}
import { useState } from "react";
import "./T-005.css";
const prices = [{ "monthly": "15", "annual": "12" }, { "monthly": "39", "annual": "31.20" }, { "monthly": "89", "annual": "71.20" }];
function NeonBillingSwitch() {
  const [annual, setAnnual] = useState(false);
  return <div className="demo-stage nb-root" role="region" aria-label="Billing Cycle Selector"><div className="nb-panel"><div className="nb-header"><h3 className="nb-title">{"Neon Cloud Tier"}</h3><div className="nb-toggle-wrap" role="group" aria-label="Billing frequency"><button type="button" data-cycle="monthly" aria-label="Select monthly billing" className={"nb-cycle-btn" + (!annual ? " nb-active" : "")} aria-pressed={!annual} onClick={() => setAnnual(false)}>{"Monthly"}</button><button type="button" data-cycle="annual" aria-label="Select annual billing with discount" className={"nb-cycle-btn" + (annual ? " nb-active" : "")} aria-pressed={annual} onClick={() => setAnnual(true)}>{"Annual "}<span className="nb-badge">{"SAVE 20%"}</span></button></div></div><div className="nb-grid"><div className="nb-tier-card" data-monthly="15" data-annual="12"><span className="nb-tier-name">{"Developer"}</span><div className="nb-tier-price"><span className="nb-currency">{"$"}</span><span className="nb-val">{prices[0][annual ? "annual" : "monthly"]}</span><span className="nb-unit">{"/mo"}</span></div><p className="nb-tier-detail">{"Standard fast isolated container instances."}</p></div><div className="nb-tier-card nb-featured" data-monthly="39" data-annual="31.20"><div className="nb-popular-tag">{"POPULAR"}</div><span className="nb-tier-name">{"Startup"}</span><div className="nb-tier-price"><span className="nb-currency">{"$"}</span><span className="nb-val">{prices[1][annual ? "annual" : "monthly"]}</span><span className="nb-unit">{"/mo"}</span></div><p className="nb-tier-detail">{"High performance edge global distribution."}</p></div><div className="nb-tier-card" data-monthly="89" data-annual="71.20"><span className="nb-tier-name">{"Enterprise"}</span><div className="nb-tier-price"><span className="nb-currency">{"$"}</span><span className="nb-val">{prices[2][annual ? "annual" : "monthly"]}</span><span className="nb-unit">{"/mo"}</span></div><p className="nb-tier-detail">{"Dedicated compute clusters and SLAs."}</p></div><p className="nb-billing-note" aria-live="polite">{annual ? "Monthly equivalent, billed annually. Fictional demo prices." : "Billed monthly. Fictional demo prices."}</p></div></div></div>;
}
export {
  NeonBillingSwitch as default
};
.nb-root {
  box-sizing: border-box;
  width: 100%;
  max-width: 560px;
  max-height: 420px;
  min-width: 0;
  margin: 0 auto;
  padding: 16px;
  background: radial-gradient(circle at 50% 10%, #150d24 0%, #07050d 100%);
  border-radius: 16px;
  border: 1px solid #2e1c4a;
  box-shadow: 0 16px 36px rgba(0, 0, 0, 0.7);
  font-family: system-ui, -apple-system, sans-serif;
  color: #f1e8ff;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.nb-root *, .nb-root *::before, .nb-root *::after {
  box-sizing: border-box;
  min-width: 0;
}
.nb-root .nb-panel {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.nb-root .nb-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
}
.nb-root .nb-title {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  color: #ffffff;
  text-shadow: 0 0 10px rgba(168, 85, 247, 0.6);
}
.nb-root .nb-toggle-wrap {
  display: flex;
  background: #11091e;
  padding: 3px;
  border-radius: 10px;
  border: 1px solid #3b1d63;
}
.nb-root .nb-cycle-btn {
  appearance: none;
  border: none;
  background: transparent;
  color: #a78bfa;
  padding: 6px 14px;
  border-radius: 8px;
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 6px;
}
.nb-root .nb-cycle-btn.nb-active {
  background: #7e22ce;
  color: #ffffff;
  box-shadow: 0 0 12px rgba(126, 34, 206, 0.8);
}
.nb-root .nb-cycle-btn:focus-visible {
  outline: 2px solid #c084fc;
  outline-offset: 2px;
}
.nb-root .nb-badge {
  font-size: 9px;
  background: #06b6d4;
  color: #041f28;
  font-weight: 800;
  padding: 2px 5px;
  border-radius: 4px;
}
.nb-root .nb-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 10px;
}
.nb-root .nb-tier-card {
  position: relative;
  background: #130a21;
  border: 1px solid #2d1847;
  border-radius: 10px;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.nb-root .nb-tier-card.nb-featured {
  border-color: #a855f7;
  box-shadow: 0 0 16px rgba(168, 85, 247, 0.25);
}
.nb-root .nb-popular-tag {
  position: absolute;
  top: -8px;
  right: 10px;
  background: #a855f7;
  color: #ffffff;
  font-size: 8px;
  font-weight: 800;
  padding: 2px 6px;
  border-radius: 4px;
  letter-spacing: 0.5px;
}
.nb-root .nb-tier-name {
  font-size: 13px;
  font-weight: 700;
  color: #c084fc;
}
.nb-root .nb-tier-price {
  font-size: 22px;
  font-weight: 800;
  color: #ffffff;
  display: flex;
  align-items: baseline;
}
.nb-root .nb-currency {
  font-size: 14px;
  color: #d8b4fe;
}
.nb-root .nb-unit {
  font-size: 11px;
  color: #8b5cf6;
  font-weight: 500;
}
.nb-root .nb-tier-detail {
  margin: 0;
  font-size: 10px;
  color: #a78bfa;
  line-height: 1.3;
}
@media (prefers-reduced-motion: no-preference) {
  .nb-root .nb-cycle-btn {
    transition: background 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
  }
  .nb-root .nb-tier-card {
    transition: border-color 0.2s ease, transform 0.2s ease;
  }
  .nb-root .nb-val {
    transition: transform 0.2s ease;
  }
}
.nb-root{max-height:none;--demo-accent:#c084fc;border-color:var(--demo-accent)}.nb-root button:focus-visible{outline-color:var(--demo-accent)}
.nb-root .nb-billing-note{font-size:10px;color:#c4b5fd;margin:0}.nb-root .nb-grid{grid-template-columns:repeat(3,minmax(0,1fr))}.nb-root .nb-tier-card{padding:10px 8px}.nb-root .nb-tier-name{font-size:clamp(10px,2.5vw,13px)}.nb-root .nb-tier-price{font-size:clamp(17px,4vw,22px)}

仕組みとカスタマイズHow It Works & Customization

仕組みHow it works

Scoped CSS creates the visual design; small vanilla JavaScript handlers update the local demo state.

スコープ化したCSSで描画し、Vanilla JavaScriptでデモ内の状態だけを更新します。

カスタマイズ方法Customization

Accent color for the panel border and keyboard focus ring.

パネルの枠線とキーボードフォーカスの色を変更します。

注意点Caveats

The sample content is fictional. No external assets or libraries are required. Motion follows the operating system preference. Demo labels are English; surrounding documentation supports Japanese and English.

デモ内容は架空です。外部素材・ライブラリは不要。OSの動きを減らす設定に対応します。デモ内のラベルは英語、解説は日英対応です。

よくある質問 Frequently Asked Questions

Does this demo need external libraries? 外部ライブラリは必要ですか?

The sample content is fictional. No external assets or libraries are required. Motion follows the operating system preference. Demo labels are English; surrounding documentation supports Japanese and English.

デモ内容は架空です。外部素材・ライブラリは不要。OSの動きを減らす設定に対応します。デモ内のラベルは英語、解説は日英対応です。

AIへの指示テンプレート AI Prompt Template

以下をAIに貼り付けると実装を依頼できます。 Paste the following into your AI assistant to request implementation.