diff --git a/src/renderer/components/button.ts b/src/renderer/components/button.ts
new file mode 100644
index 0000000..fda59c8
--- /dev/null
+++ b/src/renderer/components/button.ts
@@ -0,0 +1,4 @@
+
+export const SettingButton = (text: string, id?: string, type: string = 'secondary') => {
+    return `<setting-button ${type ? `data-type="${type}"` : ''} ${id ? `id="${id}"` : ''}>${text}</setting-button>`;
+}
\ No newline at end of file
diff --git a/src/renderer/components/index.ts b/src/renderer/components/index.ts
new file mode 100644
index 0000000..7fd2fe8
--- /dev/null
+++ b/src/renderer/components/index.ts
@@ -0,0 +1,5 @@
+export * from './list';
+export * from './item';
+export * from './button';
+export * from './switch';
+export * from './select';
diff --git a/src/renderer/components/item.ts b/src/renderer/components/item.ts
new file mode 100644
index 0000000..2f054a0
--- /dev/null
+++ b/src/renderer/components/item.ts
@@ -0,0 +1,10 @@
+
+export const SettingItem = (title: string, subtitle?: string, action?: string, id?: string, visible: boolean = true) => {
+    return `<setting-item ${id ? `id="${id}"` : ''} ${!visible ? 'is-hidden' : ''}>
+    <div>
+        <setting-text>${title}</setting-text>
+        ${subtitle ? `<setting-text data-type="secondary">${subtitle}</setting-text>` : ''}
+    </div>
+    ${action ? `<div>${action}</div>` : ''}
+</setting-item>`;
+}
\ No newline at end of file
diff --git a/src/renderer/components/list.ts b/src/renderer/components/list.ts
new file mode 100644
index 0000000..af2d8ff
--- /dev/null
+++ b/src/renderer/components/list.ts
@@ -0,0 +1,10 @@
+
+export const SettingList = (items: string[], title?: string, isCollapsible: boolean = false, direction: string = 'column') => {
+    return `<setting-section ${title && !isCollapsible ? `data-title="${title}"` : ''}>
+    <setting-panel>
+        <setting-list ${direction ? `data-direction="${direction}"` : ''} ${isCollapsible ? 'is-collapsible' : ''} ${title && isCollapsible ? `data-title="${title}"` : ''}>
+            ${items.join('')}
+        </setting-list>
+    </setting-panel>
+</setting-section>`;
+}
\ No newline at end of file
diff --git a/src/renderer/components/option.ts b/src/renderer/components/option.ts
new file mode 100644
index 0000000..d134ba3
--- /dev/null
+++ b/src/renderer/components/option.ts
@@ -0,0 +1,4 @@
+
+export const SettingOption = (text: string, value?: string, isSelected: boolean = false) => {
+    return `<setting-option ${value ? `data-value="${value}"` : ''} ${isSelected ? 'is-selected' : ''}>${text}</setting-option>`;
+}
\ No newline at end of file
diff --git a/src/renderer/components/select.ts b/src/renderer/components/select.ts
new file mode 100644
index 0000000..0c33332
--- /dev/null
+++ b/src/renderer/components/select.ts
@@ -0,0 +1,11 @@
+import { SettingOption } from "./option";
+
+export const SettingSelect = (items: Array<{ text: string, value: string }>, configKey?: string, configValue?: any) => {
+    return `<setting-select ${configKey ? `data-config-key="${configKey}"` : ''}>
+    <div>
+        ${items.map((e, i) => {
+            return SettingOption(e.text, e.value, (configKey && configValue ? configValue === e.value : i === 0));
+        }).join('')}
+    </div>
+</setting-select>`;
+}
\ No newline at end of file
diff --git a/src/renderer/components/switch.ts b/src/renderer/components/switch.ts
new file mode 100644
index 0000000..1978a47
--- /dev/null
+++ b/src/renderer/components/switch.ts
@@ -0,0 +1,9 @@
+
+export const SettingSwitch = (configKey?: string, isActive: boolean = false, extraData?: Record<string, string>) => {
+    return `<setting-switch 
+    ${configKey ? `data-config-key="${configKey}"` : ''} 
+    ${isActive ? 'is-active' : ''} 
+    ${extraData ? Object.keys(extraData).map(key => `data-${key}="${extraData[key]}"`) : ''} 
+    >
+</setting-switch>`;
+}
\ No newline at end of file
diff --git a/src/renderer.ts b/src/renderer/index.ts
similarity index 100%
rename from src/renderer.ts
rename to src/renderer/index.ts