Forms

Date pickers, form alignment, and input patterns.

Single Column

We'll never share your email.
<form method="post">
    {% csrf_token %}

    <div class="form-row">
        <div class="form-group">
            <label for="full_name">Full Name</label>
            <input type="text" id="full_name" name="full_name"
                   class="vTextField" placeholder="Jane Smith">
        </div>
    </div>

    <div class="form-row">
        <div class="form-group">
            <label for="email">Email</label>
            <input type="email" id="email" name="email"
                   class="vTextField" placeholder="jane@example.com">
            <span class="helptext">Help text below input</span>
        </div>
    </div>

    <div class="form-row">
        <div class="form-group">
            <label for="bio">Bio</label>
            <textarea id="bio" name="bio" class="vLargeTextField"
                      rows="3" placeholder="..."></textarea>
        </div>
    </div>

    <div class="form-row" style="margin-top: 16px;">
        <button type="button" class="button button-secondary">Cancel</button>
        <button type="submit" class="button button-primary">Save</button>
    </div>
</form>

Two-Column Alignment

Optional — used for account recovery
<form method="post">
    {% csrf_token %}

    <div class="form-row form-row-2col">
        <div class="form-group">
            <label for="first_name">First Name</label>
            <input type="text" id="first_name" name="first_name"
                   class="vTextField" placeholder="Jane">
        </div>
        <div class="form-group">
            <label for="last_name">Last Name</label>
            <input type="text" id="last_name" name="last_name"
                   class="vTextField" placeholder="Smith">
        </div>
    </div>

    <div class="form-row form-row-2col">
        <div class="form-group">
            <label for="department">Department</label>
            <select id="department" name="department" class="vTextField">
                <option value="">Choose...</option>
                <option value="eng">Engineering</option>
            </select>
        </div>
        <div class="form-group">
            <label for="role">Role</label>
            <select id="role" name="role" class="vTextField">
                <option value="">Choose...</option>
                <option value="ic">Individual Contributor</option>
            </select>
        </div>
    </div>

    <div class="form-row" style="margin-top: 16px;">
        <button type="button" class="button button-secondary">Cancel</button>
        <button type="submit" class="button button-primary">Save</button>
    </div>
</form>

Date Pickers

Click the calendar icon to pick a date
Combined date and time picker
<!-- Include admin widgets CSS in extra_css block -->
<link rel="stylesheet" href="{% static 'admin/css/widgets.css' %}">

<div class="form-row form-row-2col">
    <div class="form-group">
        <label for="start_date">Start Date</label>
        <div class="date-input-wrapper">
            <input type="date" id="start_date" name="start_date"
                   class="vTextField vDateField">
            <button type="button" class="date-picker-btn"
                    data-target="start_date" aria-label="Open calendar">
                <svg viewBox="0 0 24 24" width="20" height="20"
                     fill="currentColor">
                    <path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99
                    .9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9
                    2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11z..."/>
                </svg>
            </button>
        </div>
        <span class="helptext">Click the calendar icon</span>
    </div>
    <div class="form-group">
        <label for="end_date">End Date</label>
        <div class="date-input-wrapper">
            <input type="date" id="end_date" name="end_date"
                   class="vTextField vDateField">
            <button type="button" class="date-picker-btn"
                    data-target="end_date">...</button>
        </div>
    </div>
</div>

<!-- datetime-local for combined date+time -->
<input type="datetime-local" id="meeting_time"
       class="vTextField vDateField">

<!-- JS for date picker buttons (add to extra_js block) -->
<script>
document.querySelectorAll('.date-picker-btn').forEach(function(btn) {
    btn.addEventListener('click', function() {
        var input = document.getElementById(this.dataset.target);
        if (input.showPicker) {
            input.showPicker();
        } else {
            input.focus();
            input.click();
        }
    });
});
</script>

File & Image Upload

Standard file picker
Drag & drop an image or click to browse
JPG, PNG, GIF, WebP
Drag & drop a document or click to browse
PDF, DOC, DOCX, TXT
<!-- Basic file input -->
<input type="file" id="attachment" name="attachment" class="vTextField">

<!-- Drag & drop upload zone -->
<div class="file-upload-wrapper">
    <div class="file-upload-dropzone" id="avatar-dropzone">
        <svg viewBox="0 0 24 24" width="32" height="32"
             fill="currentColor"
             style="color: var(--body-quiet-color);">
            <path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2
            2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5
            3.01L14.5 12l4.5 6H5l3.5-4.5z"/>
        </svg>
        <span class="dropzone-text">
            Drag & drop an image or click to browse
        </span>
        <span class="dropzone-filename" id="avatar-filename"
              style="display: none;"></span>
        <input type="file" id="avatar" name="avatar"
               accept="image/*" class="file-upload-input">
    </div>
</div>

<!-- CSS needed (add to extra_css block) -->
<style>
.file-upload-wrapper { width: 100%; }
.file-upload-dropzone {
    position: relative;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    gap: 8px; padding: 24px 16px;
    border: 2px dashed var(--card-border);
    border-radius: var(--radius-md);
    background: var(--body-bg); cursor: pointer;
}
.file-upload-dropzone:hover,
.file-upload-dropzone.dragover {
    border-color: var(--primary);
    background: color-mix(in srgb, var(--primary) 5%, var(--body-bg));
}
.file-upload-input {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    opacity: 0; cursor: pointer;
}
</style>

<!-- JS for dropzone (add to extra_js block) -->
<script>
document.querySelectorAll('.file-upload-dropzone')
  .forEach(function(zone) {
    var input = zone.querySelector('.file-upload-input');
    var text = zone.querySelector('.dropzone-text');
    var filename = zone.querySelector('.dropzone-filename');

    input.addEventListener('change', function() {
        if (this.files.length > 0) {
            text.style.display = 'none';
            filename.textContent = this.files[0].name;
            filename.style.display = '';
        }
    });

    zone.addEventListener('dragover', function(e) {
        e.preventDefault();
        zone.classList.add('dragover');
    });
    zone.addEventListener('dragleave', function() {
        zone.classList.remove('dragover');
    });
    zone.addEventListener('drop', function(e) {
        e.preventDefault();
        zone.classList.remove('dragover');
        if (e.dataTransfer.files.length > 0) {
            input.files = e.dataTransfer.files;
            input.dispatchEvent(new Event('change'));
        }
    });
});
</script>

Theme Settings

Choose the color mode for your app.

The accent color for your app.

Choose the font family that fits your app.

Choose the gray shade for your app.

Choose the border radius factor for your app.

Choose the page layout for your app.