Domma Flags

Nation flags as crisp, scalable inline SVG - keyed by ISO code, themable into rectangular, rounded, square or circular shapes. An opt-in module. Click any flag to copy.

One flag, four shapes

One flag, four shapes
<div class="flag-shapes-demo" id="shapes-demo"></div>
/**
 * One flag, four shapes - from public/showcase/flags.
 */
export function mount(root) {
    const shapesHost = $(root).find('#shapes-demo');
    ['rect', 'rounded', 'square', 'circle'].forEach(shape => {
            const fig = document.createElement('figure');
            fig.appendChild(FL.render('gb', {size: 72, shape, border: true}));
            const cap = document.createElement('figcaption');
            cap.textContent = shape;
            fig.appendChild(cap);
            shapesHost.append(fig);
        });
}
One flag, four shapes
<div class="flex flex-wrap items-center gap-3 mb-4 sx-gallery-controls">
            <input type="text" class="flag-search-input form-input" id="search" placeholder="Search by name or code…" aria-label="Search flags">
            <div class="flex gap-2 items-center">
                <label class="text-sm opacity-75">Shape</label>
                <select id="shape" class="form-select" style="width:auto" aria-label="Flag shape">
                    <option value="rect">Rectangular</option>
                    <option value="rounded">Rounded</option>
                    <option value="square">Square</option>
                    <option value="circle">Circle</option>
                </select>
                <label class="text-sm opacity-75 ml-2">Size</label>
                <select id="size" class="form-select" style="width:auto" aria-label="Flag size">
                    <option value="32">32</option>
                    <option value="48" selected="">48</option>
                    <option value="64">64</option>
                </select>
            </div>
        </div>
<div id="gallery"></div>
<div class="flag-no-results" id="no-results" style="display:none">No flags match your search.</div>
/**
 * One flag, four shapes - from public/showcase/flags.
 */
export function mount(root) {
        // ---- Gallery ----
    const regions = FL.listRegions();
    let currentShape = 'rect';
    let currentSize = 48;
    function renderGallery(query = '') {
            const gallery = $(root).find('#gallery');
            gallery.html('');
            const matches = query ? FL.search(query) : null;
            let shown = 0;

            _.each(regions, (meta, key) => {
                const codes = meta.codes.filter(c => !matches || matches.includes(c));
                if (!codes.length) {
                    return;
                }
                shown += codes.length;

                const title = document.createElement('h2');
                title.className = 'flag-region-title';
                title.textContent = meta.name;
                gallery.append(title);

                const grid = document.createElement('div');
                grid.className = 'flag-grid';
                codes.forEach(code => {
                    const cell = document.createElement('div');
                    cell.className = 'flag-cell';
                    cell.appendChild(FL.render(code, {size: currentSize, shape: currentShape, border: true}));
                    const name = document.createElement('div');
                    name.className = 'flag-name';
                    name.textContent = FL.name(code);
                    const cd = document.createElement('div');
                    cd.className = 'flag-code';
                    cd.textContent = code;
                    cell.append(name, cd);
                    $(cell).on('click', () => copy(code));
                    grid.appendChild(cell);
                });
                gallery.append(grid);
            });

            $(root).find('#no-results').css('display', shown ? 'none' : 'block');
        }
    function copy(code) {
            navigator.clipboard.writeText(`data-flag="${code}"`).then(() => {
                E.toast(`Copied: ${code}`, {type: 'success', position: 'bottom-center', duration: 1800});
            });
        }
        // Controls
    let t;
    $(root).find('#search').on('input', function () {
            clearTimeout(t);
            const v = $(this).val();
            t = setTimeout(() => renderGallery(v), 180);
        });
    $(root).find('#shape').on('change', function () {
            currentShape = $(this).val();
            renderGallery($(root).find('#search').val());
        });
    $(root).find('#size').on('change', function () {
            currentSize = parseInt($(this).val(), 10);
            renderGallery($(root).find('#search').val());
        });
        // Initial render
    renderGallery();
}

Usage

HTML data attributes

<!-- after domma.min.js -->
<script src="dist/domma-flags.min.js"></script>

<span data-flag="gb"></span>
<span data-flag="jp" data-flag-shape="circle"
      data-flag-size="48" data-flag-border></span>

<script>FL.scan();</script>

JavaScript API

// Render an SVG element
const svg = FL.render('fr', { size: 48, shape: 'rounded' });
document.body.appendChild(svg);

// Inject into a target
FL.inject('#country', 'de', { shape: 'circle', border: true });

// Search & list
FL.search('united');     // ['gb', 'us', 'ae']
FL.list('europe');       // ['gb', 'fr', 'de', ...]
FL.name('br');           // 'Brazil'

// Register your own / override
FL.register('eu', { name: 'European Union', region: 'europe',
    bg: '#003399',
    overlays: [{ type: 'star', cx: 30, cy: 20, r: 4, fill: '#FFCC00' }] });

Tutorial: a country picker

Tutorial: a country picker
// Build options from the registry, sorted by name
                const codes = _.sortBy(FL.list(), c => FL.name(c));
                codes.forEach(code => {
                $('#country-picker').append(
                `<option value="${code}">${FL.name(code)}</option>`
                );
                });

                // React to selection
                $('#country-picker').on('change', function () {
                const code = $(this).val();
                FL.inject('#picker-flag', code,
                { size: 40, shape: 'rounded', border: true, position: 'replace' });
                $('#picker-name').text(FL.name(code));
                $('#picker-code').text(code.toUpperCase());
                });
<div class="row">
    <div class="col-5">
        <div class="card">
            <div class="card-body">
                <label class="d-block mb-2 font-semibold">Choose a country</label>
                <select id="country-picker" class="dm-select w-full"></select>
                <div class="d-flex align-items-center gap-3 mt-4">
                    <span id="picker-flag"></span>
                    <div>
                        <div id="picker-name" class="font-semibold"></div>
                        <code id="picker-code" class="text-sm opacity-65"></code>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="col-7">
        <pre class="code-block language-javascript"><code>// Build options from the registry, sorted by name
                const codes = _.sortBy(FL.list(), c =&gt; FL.name(c));
                codes.forEach(code =&gt; {
                $('#country-picker').append(
                `&lt;option value="${code}"&gt;${FL.name(code)}&lt;/option&gt;`
                );
                });

                // React to selection
                $('#country-picker').on('change', function () {
                const code = $(this).val();
                FL.inject('#picker-flag', code,
                { size: 40, shape: 'rounded', border: true, position: 'replace' });
                $('#picker-name').text(FL.name(code));
                $('#picker-code').text(code.toUpperCase());
                });</code></pre>
    </div>
</div>
/**
 * Tutorial: a country picker - from public/showcase/flags.
 */
export function mount(root) {
        // ---- Tutorial picker ----
    _.sortBy(FL.list(), c => FL.name(c)).forEach(code => {
            $(root).find('#country-picker').append(`<option value="${code}">${FL.name(code)}</option>`);
        });
    function updatePicker() {
            const code = $(root).find('#country-picker').val();
            FL.inject(root.querySelector('#picker-flag'), code, {size: 40, shape: 'rounded', border: true, position: 'replace'});
            $(root).find('#picker-name').text(FL.name(code));
            $(root).find('#picker-code').text(code.toUpperCase());
        }
    $(root).find('#country-picker').on('change', updatePicker);
    updatePicker();
}