addPost

Make No Law

  • Reddit censors. We have free speech.

  • add_chart Add interactive content to posts.

  • follow_the_signs Follow simple rules and stay on topic.

add_chart Tier List Poll Component

Leading Voices in 2026

S
Charlie Kirk
A
JD
Tate
Trump
B
C
D
F
Marco
AOC
Newsom
Mamdani
S
Charlie Kirk
A
JD
Tate
Trump
B
C
D
F
Marco
AOC
Newsom
Mamdani
  • Creating components

    Components are pieces of HTML, CSS, and JS that can be added to posts or other components. They allow for customization by giving users custom fields to input data into. This post will discuss all parts of a component.

    Title

    The title is required, and must be 4 to 20 characters long.

    Description

    The description is required, and must be 20 to 255 characters. It appears in searches, so it should describe the purpose it serves, and any benefits and limits to using it. For instance, if you were creating a bar graph, it would be useful to mention if it allows for certain customizations such as colors of the bars, and if there is a limit on the number of bars that may be added.

    Details

    The details section is optional. It displays after a component has been selected, and above the data that is requested from the user. Relevant info about how the component works, and customization options go here. Continuing with the bar graph example, you could write that if a bar color is not specified, blue is used, and that for customization, the bars have the class 'bar' that may be edited by adding a <style> element to their post.

    Line breaks are conserved in details, so you can separate topics into different parts.

    User-Entered Data

    User-Entered Data is also optional. When used, each field in the row is required.

    All user-entered data becomes a part of an object for your code. Each component has a unique id, and this id is embedded into the source variable name of this user-entered data object. If the component's id is iOK0H, the source variable for your component is dataiOK0H (will be used as an example throughout this doc). This is still the variable name you should use in your code when accessing component data.

    Each component also has a config object named dataiOK0H_config. It includes created, previewHtml, componentId, and localId. On the full post page it also includes fragment, which is the current url fragment without the leading #.

    Store Data

    We allow saving data per user via the store data field. To update the store data field for a user, see the "Global Functions" -> "Store Data" section. You can edit the rules and keys for a store data field by clicking the "Edit Fields and Rules" button. The data is provided to a component in this format (if component id is iOK0H and property name is pollValues):

    dataiOK0H['pollValues'] = {
        "userInput": {
          "poll_question": [null,1],
          "poll_user_count": 1
        },
        "userInputMeta": {
          "created": "2026-07-07 05:52:00",
          "modified":"2026-07-07 05:52:00"
        },
        "aggregateValues": {
          "poll_question": [null,1],
          "poll_user_count": 1
        }
    };

    userInputMeta's date and time properties are when the userInput values were saved for this user. They are in UTC. If no values have been supplied for this user, it will look like:

    dataiOK0H['pollValues'] = {
        "userInput": {
          "poll_question": [],
          "poll_user_count": null
        },
        "userInputMeta": {
          created: null,
          modified: null
        },
        "aggregateValues": {
          "poll_question": [],
          "poll_user_count": null
        }
    };


    Component Collisions

    To allow for multiple instances of your component to be added to one post, every instance of dataiOK0H is still rewritten before your code runs so that each instance gets its own runtime variable. Use dataiOK0H in your source code so the system can rewrite it correctly.

    When a component is added to a post, it is given a localId (starts at 0 and auto-increments). This localId is visible in the code editor, so the user can use it if necessary (described later). If your component is the third added, it will have a localId of 2. Before your code is run, instances of dataiOK0H are rewritten to a runtime-specific variable that includes the localId, and it may also include an added random string. Because of that, do not depend on the final rewritten variable name being stable across renders.

    If you need stable values for ids, class names, fragment targets, or other generated markup, use dataiOK0H_config.componentId and dataiOK0H_config.localId.

    Global shared styles

    Loading Icon
    You can show a loading icon by adding class fg-loading-icon to an element with no other children. A loading icon is rendered with css, and by default is 30px wide and 30px tall, but you may customize this. You may also customize the colors of it.

    We will be adding more global shared styles so components can all have the same look and feel. Please check back continually for updates to this section.

    Config Values

    When a component is rendered, the site also exposes a runtime config object. This gives your component a few useful values about the current render context, like the component instance id and the current max render height.

    Example:

    window.dataAB12_config = {
       created: 1713990000000,
       previewHtml: "<p>Example post content</p>",
       fragment: "",
       maxHeight: 300,
       componentId: "AB12",
       localId: "0",
    };


    Global Functions

    Store Data

    If you choose the Store Data field type, that field must be at the top level. Store Data lets a component load saved values for the current user and aggregate values returned by the backend. The configured keys for that field become data properties, and those keys may only contain letters, numbers, and underscores.

    At runtime, call window.fgStoreData. It return a Promise. On success, the requested property on your component data object is updated with an object containing userInput and aggregateValues. In this case, scores is the "Data Property Name" value for this Store Data field in the User-Entered Data.

    window.fgStoreData('load', 'dataiOK0H', 'scores').then(function () {
         console.log(dataiOK0H.scores.userInput);
         console.log(dataiOK0H.scores.aggregateValues);
    });

    To save data, call window.fgStoreData with an additional parameter, which must be an object with a userInput property. The properties allowed on the userInput are set for the field by clicking the "Edit Fields and Rules" button, and adding to the Fields section. The Key for each field make up the exact properties we will allow.

    window.fgStoreData('save', 'dataiOK0H', 'scores', {
        userInput: {
          score: 7
        }
    }).then(function () {
         console.log(dataiOK0H.scores.userInput);
    });

    Saving requires the user to be logged in. In previews, Store Data uses the configured test payload until the component is attached to a post.

    window.fgStoreData returns a Promise and may reject if the request fails, the field cannot be identified, the supplied data is invalid, or a save is attempted while logged out. Components should handle these errors.

    window.fgStoreData('save', 'dataiOK0H', 'scores', {
       userInput: {
         score: 7
       }
    }).then(function () {
       console.log(dataiOK0H.scores.userInput);
    }).catch(function (error) {
       console.error(error.message);
    });

    When a logged-out user attempts to save, the signup flow is opened and the Promise rejects. Loading does not require the user to be logged in.

    Force Signup Flow

    window.fgRequireSignup

    This function triggers the signup modal flow. Use it when interacting with buttons that will later require data to be saved

    Add Component to New Post

    window.fgAddComponentToPost

    This function opens the new post page and opens the Add Component modal with the calling component selected. Pass the component's config object so the correct component can be identified.

    window.fgAddComponentToPost(dataiOK0H_config);

    You may also pass the component id directly:

    window.fgAddComponentToPost(dataiOK0H_config.componentId);

    The function returns true

    Approval of components

    Unlike posts, components cannot be used or seen in search results until they are approved. This is to prevent malicious code from becoming widespread before being deleted, and potentially diminishing the UX for users visiting posts that had a component deleted retroactively. To ensure your component is approved, refrain from using external JS files that could be changed maliciously in the future. Only repositories on unpkg.com - like jQuery, React, and other npm packages - will be allowed. Aside from common social media, all other script urls are blocked by our Content-Security-Policy. If you have another site you'd like to include scripts from, please submit feedback (in the dropdown menu in the upper right hand corner when you log in).

    Add the following to enable react:

    <script src='https://unpkg.com/react/umd/react.production.min.js'></script> <script src='https://unpkg.com/react-dom/umd/react-dom.production.min.js'></script> 

    When testing, use the following:

    <script src='https://unpkg.com/react/umd/react.development.js'></script> <script src='https://unpkg.com/react-dom/umd/react-dom.development.js'></script> 


    Versioning

    When a new version of a component is approved, changes will not automatically propagate to posts using that component. Posts will have to be updated individually. This was done because updated components may no longer fit in as well with the post, and can change user-entered data formatting.

    Coding details

    Use dataiOK0H for your component's actual data. Use dataiOK0H_config.componentId and dataiOK0H_config.localId when you need stable html ids, class names, or fragment targets.

    const sectionId = `${dataiOK0H_config.componentId}-${dataiOK0H_config.localId}-results`;

    On the full post page, dataiOK0H_config.fragment contains the current url fragment without the leading #. This can be used if your component needs to react to a specific fragment when the post is opened.

    Linking to fragments in posts

    If you want a button or link inside a rendered component to open the full post and jump to a specific element, add data-click-bridge-fragment to the clicked element. The value should match the target element's id, with or without the leading #.

    <button data-click-bridge-fragment='results-section'>View Results</button> <a href='#' data-click-bridge-fragment='results-section'>View Results</a>

    The target element should use a stable id, ideally one built from dataiOK0H_config.componentId and dataiOK0H_config.localId. If you only want to open the post without adding a hash, use data-click-bridge-navigate.

    Caveats

    Single Page App with Server Side Rendering

    Because pages are loaded two different ways, you must plan accordingly. If you need to wait for the page to load to examine or manipulate elements, you will have to check to see if the document has loaded already before adding a window load event listener:

    // when using React
    componentDidMount() {
       if (document.readyState !== 'complete') {
         this.listenerSet = true;
         window.addEventListener('load', this.loadData);
       } else {
         this.listenerSet = false;
         this.loadData();
       }
    }

    For removing the listener in React:

    componentWillUnmount() {
       if (this.listenerSet) {
         window.removeEventListener('load', this.loadData);
       }
    }

    Without React:

    if (document.readyState !== 'complete') {
       window.addEventListener('beforeunload', function (event) {
         window.removeEventListener('load', this.loadData);
       });
    }


    Interactive Authoring Components

    Enabling interactive authoring allows a component to replace the normal Add Component data form with a full-width interactive preview. The component can provide its own controls for updating User-Entered Data.

    The optional Add Component Preview Code is appended to the component only while it is displayed in the Add Component preview. It can be used for controls and behavior needed during authoring but should not appear in the published component.

    The interactive-authoring functions below return Promises. Although the global function names may exist in other render contexts, requests will reject unless interactive authoring is enabled and the component is currently running in an interactive Add Component preview.

    Update User-Entered Data

    window.fgUpdateUserData updates a User-Entered Data field. The resolved value is the value accepted after validation and sanitization.

    window.fgUpdateUserData(
       'dataiOK0H',
       'heading',
       'New heading'
    ).then(function (result) {
       console.log(result.value);
    }).catch(function (error) {
       console.error(error.message);
    });

    For a field inside a repeating collection, pass its collection index as the fourth argument.

    window.fgUpdateUserData('dataiOK0H', 'heading', 'Second heading', 1);


    Pick an Image

    window.fgPickUserDataImage opens the operating-system image picker for an image field. Image uploads require the user to be logged in. For an image inside a repeating collection, supply its collection index.

    Opening the picker does not mean an upload has started. Use the optional onStatus callback to manage loading:

    • uploading: A file was selected and uploading started.

    • done: The upload succeeded.

    • error: The upload failed.

    • superseded: An abandoned picker request was replaced by a newer request.


    Do not show a loading indicator or disable the image control immediately after calling fgPickUserDataImage. Only do so while the status is uploading.


    var imageUploadInProgress = false;

    function chooseImage() {

    if (imageUploadInProgress) {

    return;

    }

    window

    .fgPickUserDataImage({

    runtimeWindowVar: "dataiOK0H",

    dataProperty: "image",

    collectionIndex: 0, // omit for a top-level image field

    onStatus: function (update) {

    imageUploadInProgress =

    update.status === "uploading";

    document.querySelector(

    ".image-loading-icon",

    ).hidden = !imageUploadInProgress;

    document.querySelector(

    ".image-upload-button",

    ).disabled = imageUploadInProgress;

    },

    })

    .then(function (result) {

    imageUploadInProgress = false;

    // The image value accepted by the parent.

    console.log(result.value);

    })

    .catch(function (error) {

    imageUploadInProgress = false;

    if (error.status === "superseded") {

    return;

    }

    console.error(error.message);

    });

    }

    Operating-system file pickers do not reliably report when the user closes them without selecting a file. Therefore, there is no cancelled status.

    If the picker is abandoned, the image control should remain clickable. When clicked again, the new request replaces the abandoned request. The old Promise rejects with error.status set to superseded. This is not an upload failure and should normally be ignored.

    The positional form remains supported, but does not provide status callbacks:

    window
        .fgPickUserDataImage("dataiOK0H", "image", 0)
        .then(function (result) {
            console.log(result.value);
        })
        .catch(function (error) {
            console.error(error.message);
        });


    Change Collection Items

    These functions add, remove, or reorder repetitions of a Collection field. Collection minimum and maximum limits are enforced. The data property must belong to the parent Collection field rather than one of its child fields.

    window.fgAddCollectionItem('dataiOK0H', 'rows');
    window.fgRemoveCollectionItem('dataiOK0H', 'rows', 1);
    window.fgReorderCollectionItem('dataiOK0H', 'rows', 0, 2);

    Each collection function returns a Promise and rejects if the collection, index, or requested operation is invalid.

    Displaying Component Results in Comments

    Components with a Store Data field can let users include their current saved result with a comment. The user must explicitly enable this when creating or editing the comment. Results use the user’s current live Store Data rather than a snapshot.

    Comment result label is required and should be a short noun or phrase, such as vote, score, or submission. It appears in text such as Include your vote with this comment and @username's vote.

    Comment result renderer is optional HTML, CSS, and JavaScript for displaying a small, read only version of the result. If it is empty, the full component is rendered instead.

    The renderer receives the normal component data object, including the comment author’s disclosed Store Data, and the normal config object. For component iOK0H, use dataiOK0H and dataiOK0H_config. In comment results, dataiOK0H_config.renderContext is comment-display.

    var selection =   dataiOK0H.pollSelection.userInput.poll_question;
    var selectedIndex = selection.indexOf(1);
    var selectedOption = dataiOK0H.options[selectedIndex];

    Comment results are sandboxed and read-only. Store Data save, set, and update operations are blocked. Keep the renderer compact and exclude editing controls or unrelated component details.

    Use Update preview in the component editor to refresh the comment renderer preview after changing its HTML or test data.

    Only one component result can be included with a comment. The pinned Store Data component is preferred; otherwise the post must contain exactly one Store Data component.

    Default Image Screenshots

    A component can supply a post's thumbnail by screenshot. Enable Use a component screenshot as the post default image on the component.

    If the component has a Store Data field, you can also choose when the screenshot runs: when the post is created or edited, or periodically after store data changes.

    When a screenshot is taken, the component is rendered alone, and the renderContext is default-image-screenshot.

    Put an attribute data-fg-screenshot-content on exactly one element. This is what the screenshot will capture. More than one of those attributes will fail the capture.

    <div data-fg-screenshot-content>
      <canvas id="chart"></canvas>
    </div>

    After all asynchronous rendering is finished (loaded store data, charts, canvases, late layout), call window.fgScreenshotReady(). The capture waits for this signal. If you never call it, the screenshot fails.

    if (dataiOK0H_config.renderContext === 'default-image-screenshot') {
      window.fgStoreData('load', 'dataiOK0H', 'scores').then(function () {
        drawChart();
        window.fgScreenshotReady();
      }).catch(function () {
        window.fgScreenshotReady();
      });
    }

    Calling it more than once is safe. Images and fonts in the component are waited for after this call, so you only need to signal when your own JS rendering is done.

    Keep the screenshot target compact. Hide editing controls and other chrome when renderContext is default-image-screenshot.

    MakeNoLaw's avatar@MakeNoLawlocal_police
    Moderator of Make No Law Help
    05 months ago5mo
    Which spongebob character are you?
    MakeNoLaw's avatar@MakeNoLaw
    04 months ago4mo
    Most impactful voices in 2026
    MakeNoLaw's avatar@MakeNoLawlocal_police
    Moderator of Tier Lists
    32 months ago2mo
  • People on welfare are America's 3rd worlders

    They would live in straw huts if they lived in their own country.

    MakeNoLaw's avatar@MakeNoLawlocal_police
    Moderator of Free Speech
    01 month ago1mo
  • Grokpedia > Wikipedia

    Stop donating to Wikipedia.

    Woke in the Wild - Grokpedia > Wikipedia
    MakeNoLaw's avatar@MakeNoLawlocal_police
    Moderator of Woke in the Wild
    31 month ago1mo
  • "Allahu Akbar" is a worse slur than the n word

    "Allahu Akbar" has killed millions. Cancel anyone who says the "A" phrase. It represents murder and pedophilia which are the pillars of islam.

    MakeNoLaw's avatar@MakeNoLawlocal_police
    Moderator of Unpopular Opinion
    11 month ago1mo
    Going straight to the shop
    markymark's avatar@markymark
    31 month ago1mo
    ICE detentions hit a Trump-era high. 68k in concentration camps

    ICE detained more than 46k people in July and is now holding about 68k. 68k people in a concentration camp smh

    MixedUse's avatar@MixedUse
    71 month ago1mo
    scientists found a whole new monkey species in the Congo and it has an orange mouth
    F@fuckthissite
    51 month ago1mo
    Study Finds More Breast Cancer Patients Can Skip Lymph Node Surgery
    MakeNoLaw's avatar@MakeNoLaw
    11 month ago1mo
    25 states sue over Trump's new tariffs, calling them 'pretext' to replace his old ones
    L@letemcook
    51 month ago1mo
    Foreigner is selling $1k VIP tickets so fans can sit onstage, because regular concert tickets weren't weird enough
    TrumpIsAPedo's avatar@TrumpIsAPedo
    21 month ago1mo
    Abdul El-Sayed wins Michigan Democratic Senate primary

    Major win for the Democrat's progressive wing in a state neither party can take for granted. El-Sayed now has to prove that primary enthusiasm can translate into a broader coalition against the republican in November.

    stack_trace's avatar@stack_trace
    81 month ago1mo
    FBI agents fired over Trump investigation get broad backing in lawsuit against administration
    C@coldbrew
    01 month ago1mo
  • Kids with two moms get screwed

    A kid needs a dad. Not two women playing house.

    All this rainbow adoption crap is just adults putting their feelings first. Boys especially turn out soft or messed up without a man around. That's why were voting in DSA faggots now. Biology aint optional no matter what the TV says.

    Church got it right long before the activists showed up.

    usausa's avatar@usausa
    11 month ago1mo
  • DEI is just racism with better PR

    I've watched it play out in warehouses Ive worked at. Hire or promote for the checklist instead of who can actually move freight without wrecking stuff or getting hurt. Then everyone acts shocked when quality tanks and people quit or get hurt. Merit used to mean something

    T@trav
    11 month ago1mo
    Browns still won't make the obvious QB call
    C@ClosedAboveAsking
    91 month ago1mo
    Michigan Dems go all in on the far left
    P@preliftbabe
    71 month ago1mo
    Trump takes an economic victory lap in Vegas
    Trump says US exports are "totally on fire" while talking up the economy at a Las Vegas casino. A casino is certainly one place to sell Americans on the idea that the numbers are going great.

    T@trumpsucks
    11 month ago1mo
    Spider-man hits $1.15 bil in one week
    booom's avatar@booom
    31 month ago1mo
    Senate committee votes to hold Fauci in contempt for refusing to answer COVID questions
    P@permits
    51 month ago1mo
  • Rate my supplement stack

    I’ve been lifting for 16 years. My supplement stack is:

    • 1g of protein per pound per day

    • Viagra before lifting for blood circulation

    • 6g of creatine per day

    • 5g of beta alanine per day spaced out over 7 doses

    • Fish oil

    • Vitamin D

    • Multivitamin

    • Yohimbine

    MakeNoLaw's avatar@MakeNoLawlocal_police
    Moderator of Natural Bodybuilding
    41 month ago1mo
    Will Smith and Jaafar Jackson team up for Supermax

    Two FBI agents investigating an impossible murder inside a maximum security prison. Thoughts?

    S@smartafimo
    11 month ago1mo
    Running backs are getting paid again, apparently
    S@siaWaaves
    21 month ago1mo
  • a messy night out beats therapy every time

    I'm a bartender, and I see people come in stressed or fake smiling then leave after a few drinks and some bad decisions looking lighter.

    Sitting in a quiet room talking about your childhood for an hour just keeps you stuck in your head. Go dance, talk shit with strangers, make dumb choices.

    NOT saying never get help but most folks just need to get out of their apartment and stop treating every feeling like a crisis.

    glitterrr's avatar@glitterrr
    31 month ago1mo