Settings <mv-settings>
設定ページです。スクロールに追従するセクションナビゲーション、プロフィール(写真のプレビュー、検証付きのフィールド)、通知のスイッチ、セキュリティ、「unsaved changes」バー、入力して確認する危険ゾーンを備えています。
一時停止 再生
カテゴリー ブロック タイプ Web Component(<mv-settings>) ステータス 安定版 同時にインストールされるもの avatar , button , checkbox , dialog , field , input , switch Keywords settings, preferences, profile, account, form, danger-zone, scrollspy
When to use
An app needs an account settings page with section navigation that tracks scroll Users edit profile, notifications and security, and must be warned about unsaved changes Deleting an account or workspace should require typing a confirmation
Avoid when
The screen is about signing in, signing up or resetting a password → use Auth instead Only one or two preferences are edited; a dialog keeps the user in context → use Dialog instead
インストール
node scripts/add.mjs settings --out ./src/marvelous
Marvelous UI MCP サーバーを使う AI エージェント:install_components({ slugs: ["settings"], target_dir: "<absolute path>/src/marvelous", framework: "react" })。
コピーされるファイル(依存関係を含む):tokens/tokens.css, core/base.css, components/avatar/avatar.css, components/avatar/avatar.js, components/button/button.css, components/checkbox/checkbox.css, core/dom.js, core/element.js, core/motion.js, components/dialog/dialog.js, components/dialog/dialog.css, components/field/field.css, components/input/input.css, components/switch/switch.css, core/observe.js, components/settings/settings.js, components/settings/settings.css。
使い方
基本となるマークアップです。ここから属性、data-*、CSS 変数でカスタマイズしてください:
<mv-settings id="st-demo" style="height:720px;border:1px solid var(--mv-border);border-radius:var(--mv-radius-xl);overflow:hidden">
<div class="mv-settings-layout">
<nav class="mv-settings-nav" aria-label="Settings sections">
<p class="mv-settings-nav-title">Settings</p>
<ul>
<li><a href="#st-demo-profile"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="4"/><path d="M4 21a8 8 0 0 1 16 0"/></svg>Profile</a></li>
<li><a href="#st-demo-notifs"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg>Notifications</a></li>
<li><a href="#st-demo-security"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>Security</a></li>
<li><a href="#st-demo-danger" data-tone="danger"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0zM12 9v4M12 17h.01"/></svg>Danger zone</a></li>
</ul>
</nav>
<main class="mv-settings-main">
<div class="mv-settings-inner">
<header class="mv-settings-header">
<h1>Account settings</h1>
<p>Manage your profile, notifications and security for the Nova Studio workspace.</p>
</header>
<form class="mv-settings-form" novalidate>
<section class="mv-settings-section" id="st-demo-profile">
<div class="mv-settings-section-head">
<h2>Profile</h2>
<p>This information is visible to members of your workspace.</p>
</div>
<div class="mv-settings-card">
<div class="mv-settings-avatar">
<span class="mv-avatar" data-settings-avatar><img alt="Profile photo of Amara Okafor" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%2399f6e4'/%3E%3Cstop offset='1' stop-color='%230f766e'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' fill='url%28%23g%29'/%3E%3Cpath d='M10 66c1-12 10-19 22-19s21 7 22 19z' fill='%23f8fafc'/%3E%3Crect x='27' y='36' width='10' height='12' rx='4' fill='%23e7b590'/%3E%3Ccircle cx='32' cy='27' r='11' fill='%23e7b590'/%3E%3Cpath d='M20.5 26c0-8 5-13 11.5-13s11.5 5 11.5 13c-2-4-6-6.5-11.5-6.5S22.5 22 20.5 26z' fill='%237c2d12'/%3E%3C/svg%3E"><span class="mv-avatar-fallback" aria-hidden="true">AO</span></span>
<div class="mv-settings-avatar-text">
<div class="mv-settings-avatar-actions">
<label class="mv-button mv-settings-file" data-variant="outline" data-size="sm">Change photo<input type="file" name="avatar" accept="image/*" data-settings-avatar-input aria-label="Change profile photo"></label>
<button class="mv-button" type="button" data-variant="ghost" data-size="sm">Remove</button>
</div>
<small>JPG, PNG or GIF · 2 MB max</small>
</div>
</div>
<div class="mv-field-group">
<div class="mv-field-row">
<div class="mv-field">
<label class="mv-label" for="st-demo-first" data-required>First name</label>
<input class="mv-input" id="st-demo-first" name="firstName" value="Amara" required autocomplete="given-name">
</div>
<div class="mv-field">
<label class="mv-label" for="st-demo-last" data-required>Last name</label>
<input class="mv-input" id="st-demo-last" name="lastName" value="Okafor" required autocomplete="family-name">
</div>
</div>
<div class="mv-field">
<label class="mv-label" for="st-demo-email" data-required>Email address</label>
<input class="mv-input" id="st-demo-email" name="email" type="email" value="[email protected] " required autocomplete="email" aria-describedby="st-demo-email-desc">
<p class="mv-field-description" id="st-demo-email-desc">Used for sign-in and notifications.</p>
</div>
<div class="mv-field">
<label class="mv-label" for="st-demo-handle">Public handle</label>
<div class="mv-input-group">
<label class="mv-input-group-addon" data-variant="filled" for="st-demo-handle">example.com/</label>
<input class="mv-input" id="st-demo-handle" name="handle" value="amara-okafor" pattern="[a-z0-9\-]+">
</div>
</div>
<div class="mv-field">
<label class="mv-label" for="st-demo-bio" data-optional="optional">Bio</label>
<textarea class="mv-textarea" id="st-demo-bio" name="bio" style="--mv-textarea-min-rows:2">Art director with 12 years of experience across London and Toronto.</textarea>
</div>
</div>
</div>
</section>
<section class="mv-settings-section" id="st-demo-notifs">
<div class="mv-settings-section-head">
<h2>Notifications</h2>
<p>Choose what’s worth interrupting you for.</p>
</div>
<div class="mv-settings-card">
<label class="mv-choice" data-control="end">
<input type="checkbox" role="switch" class="mv-switch" name="notifMentions" checked>
<span class="mv-choice-text"><span class="mv-choice-title">Mentions and replies</span><span class="mv-choice-description">When someone mentions you in a comment.</span></span>
</label>
<label class="mv-choice" data-control="end">
<input type="checkbox" role="switch" class="mv-switch" name="notifOrders" checked>
<span class="mv-choice-text"><span class="mv-choice-title">New orders</span><span class="mv-choice-description">One notification per paid order.</span></span>
</label>
<label class="mv-choice" data-control="end">
<input type="checkbox" role="switch" class="mv-switch" name="notifMarketing">
<span class="mv-choice-text"><span class="mv-choice-title">Product updates</span><span class="mv-choice-description">One newsletter a month, never more.</span></span>
</label>
<div class="mv-settings-row">
<div><label class="mv-settings-row-title" for="st-demo-digest">Email digest</label><span class="mv-settings-row-description">A recap of workspace activity.</span></div>
<select class="mv-select" id="st-demo-digest" name="digest" data-size="sm" data-native>
<option value="daily">Daily</option>
<option value="weekly" selected>Weekly</option>
<option value="never">Never</option>
</select>
</div>
</div>
</section>
<section class="mv-settings-section" id="st-demo-security">
<div class="mv-settings-section-head">
<h2>Security</h2>
<p>Protect access to your account.</p>
</div>
<div class="mv-settings-card">
<label class="mv-choice" data-control="end">
<input type="checkbox" role="switch" class="mv-switch" name="twoFactor" checked>
<span class="mv-choice-text"><span class="mv-choice-title">Two-factor authentication</span><span class="mv-choice-description">A one-time code is required on every new sign-in.</span></span>
</label>
<div class="mv-settings-row">
<div><span class="mv-settings-row-title">Password</span><span class="mv-settings-row-description">Changed 3 months ago.</span></div>
<button class="mv-button" type="button" data-variant="outline" data-size="sm">Change</button>
</div>
<div class="mv-settings-row">
<div><span class="mv-settings-row-title">Laptop · London <span class="mv-badge" data-variant="success" data-size="sm">This device</span></span><span class="mv-settings-row-description">Desktop browser · active now</span></div>
</div>
<div class="mv-settings-row">
<div><span class="mv-settings-row-title">Phone · New York</span><span class="mv-settings-row-description">Mobile browser · 2 days ago</span></div>
<button class="mv-button" type="button" data-variant="ghost" data-size="sm">Sign out</button>
</div>
</div>
</section>
<div class="mv-settings-savebar" role="region" aria-label="Pending changes">
<span class="mv-settings-savebar-status" role="status" data-dirty="Unsaved changes" data-saved="Changes saved">Unsaved changes</span>
<button class="mv-button" type="reset" data-variant="ghost" data-size="sm">Cancel</button>
<button class="mv-button" type="submit" data-size="sm">Save</button>
</div>
</form>
<section class="mv-settings-section" id="st-demo-danger" data-tone="danger">
<div class="mv-settings-section-head">
<h2>Danger zone</h2>
<p>Irreversible actions on the workspace.</p>
</div>
<div class="mv-settings-card mv-settings-danger">
<div class="mv-settings-row">
<div><span class="mv-settings-row-title">Transfer ownership</span><span class="mv-settings-row-description">Hand the workspace over to another admin.</span></div>
<button class="mv-button" type="button" data-variant="outline" data-size="sm">Transfer</button>
</div>
<div class="mv-settings-row">
<div><span class="mv-settings-row-title">Delete workspace</span><span class="mv-settings-row-description">Projects, files and invoices will be permanently erased.</span></div>
<mv-dialog persistent>
<button class="mv-button" type="button" data-variant="destructive" data-size="sm" data-mv-open>Delete…</button>
<dialog style="--mv-dialog-width:28rem">
<header class="mv-dialog-header">
<h2 class="mv-dialog-title">Delete “Nova Studio”?</h2>
<p class="mv-dialog-description">All 24 projects, 1.2 GB of files and the billing history will be deleted for all 12 members. This can’t be undone.</p>
</header>
<div class="mv-field" style="margin-bottom:1.25rem">
<label class="mv-label" for="st-demo-confirm">To confirm, type <span class="mv-settings-confirm-code">nova-studio</span></label>
<input class="mv-input" id="st-demo-confirm" data-settings-confirm data-expected="nova-studio" autocomplete="off" spellcheck="false">
</div>
<div class="mv-dialog-footer">
<button class="mv-button" type="button" data-variant="outline" data-mv-close="cancel">Cancel</button>
<button class="mv-button" type="button" data-variant="destructive" data-mv-close="delete" data-settings-confirm-action disabled>Delete permanently</button>
</div>
</dialog>
</mv-dialog>
</div>
</div>
</section>
</div>
</main>
</div>
</mv-settings>
<script type="module">
const settings = document.getElementById("st-demo");
settings?.addEventListener("mv-save", (e) => { e.preventDefault(); setTimeout(e.detail.done, 700); });
</script>
API
Attributes
Name タイプ Default Description no-unload-warningboolean falseTurns off the browser warning shown when the page is left with unsaved changes.
Properties
Name タイプ Description stringsobject Default texts, partial override: { dirty: "Unsaved changes", saved: "Changes saved" }. data-dirty / data-saved on the status win over the defaults. dirtyboolean Read-only: true while the form has unsaved changes (to guard in-app navigation).
Methods
Name Description markSaved()Treats the current form state as saved (hides the bar; Cancel now returns to this state).
Events
Name Description mv-saveValid form submitted. detail: { data, form, done }. Call preventDefault() then done() for an async save. mv-confirmDanger-zone action confirmed. detail: { action } (the button’s data-mv-close value).
Content structure
Name Description .mv-settings-layout > .mv-settings-nav + .mv-settings-mainNavigation (#anchor links) and scrolling content. .mv-settings-sectionSection targeted by a link; its h2 names it and receives focus on navigation. data-tone="danger" for the danger zone. form.mv-settings-formTracked form: any change shows .mv-settings-savebar (reset = cancel, submit = save). [data-settings-avatar] + input[data-settings-avatar-input]Local preview of the chosen photo (object URL, no network). input[data-settings-confirm][data-expected]Confirmation input: enables [data-settings-confirm-action] when its value, spaces trimmed, equals data-expected exactly (case-sensitive); Enter then runs the action.
CSS classes
Name Description mv-settings-nav-title / -inner / -headerNavigation title, content column, page header. mv-settings-section-head / -cardSection title + description, card with divided rows. mv-settings-row / -row-title / -row-descriptionLabel row with a trailing control. mv-settings-avatar / -avatar-text / -avatar-actions / -fileProfile photo row; -file turns a label into a file button. mv-settings-savebar / -savebar-statusSticky floating bar (data-state dirty | saved). mv-settings-danger / -confirm-codeDanger-tinted card, code to type back.
Accessibility
Named navigation, current link marked aria-current (kept in view in the narrow horizontal nav); navigating moves focus to the section heading (tabindex=-1, visible focus). Sections are named by their heading. Native role=switch toggles. The unsaved-changes bar is announced through role=status without moving focus, a focused field scrolls clear of it, and focus returns to the last edited field once Save or Cancel is used. Leaving the page with unsaved changes asks for confirmation. Deletion: alertdialog (persistent), button disabled until the input matches. Forced colors: the current link uses the system highlight. Smooth scrolling is disabled with reduced motion.